December 12, 2024
–
10 min read
Security
The new Zcash Shielded App is now available, but Ledger support is limited to a ZecWallet fork by Zondax.This guide details steps to integrate Ledger into wallets like Ledger Live, Zingo, YWallet, Zashi etc.
The new Zcash Shielded Application has become officially available to the public recently.
While numerous wallets support Zcash, currently, there is no support for Ledger devices for this new app besides the development ZecWallet fork from zondax
This article provides a comprehensive overview of the essential steps required to integrate support for the Ledger Zcash Shielded App into your wallet.
This initiative is expected to benefit a wide range of wallets including Ledger Live, Zingo, YWallet, Zashi, Flexa, Nighthawk, Unstoppable etc.
In order to integrate the Ledger Zcash Shielded application into your wallet there aren’t magical recipes but we’ll make an exhaustive list of all the available resources and some general guidelines to achieve this.
You’ll need to establish communication with the device. To achieve this, Zondax provides 2 communication packages:
Rust communication package
Javascript communication package
Those packages provide the abstraction for establishing communication with your device, using a protocol called APDU (the same protocol as SIM cards). This implies that the zcash application running on the ledger device cannot initiate communication but just respond to commands.
To get the updated list of commands that the app will understand, you can check it on the APDU spec documentation
You have one extra thing to have in consideration when working with Ledger devices: private keys / highly sensitive information won’t be shared with any external party. This means that the different keys that are part of either Transparent/Sapling protocols will be computed and used on the device. You won’t have direct access to them. This means that any signing process or revealing information regarding shielded transactions must be done in the device itself.
In order to integrate our Ledger application, first you need to design a common interface that handles key management, which would provide access to view/public keys and also useful methods for signing transactions or any other operation that requires access to private keys. A common interface like this would be called a Keystore component that would integrate your current key management system in your wallet that generates keys probably in-memory, and the Ledger application.
The first step is to abstract both elements into one type that generalizes over methods for handling and using keys. In the case of Rust, it is suggested to use a sum type like Enum that holds both variants. You can check how this was implemented by Zondax in ZecWallet, where we added an enum type that abstracts the in-memory Keystore and the LedgerKeystore component while providing a common set of methods that the rest of your wallet would use for dealing with keys, either requesting view/public keys or signing transactions.
Keep in mind that the common interface must align with the security of the Ledger application, which will not allow any spending/private key to be sent out of the device. That means you cannot keep any sensitive information in-memory in your wallet implementation. If your current design relies on this, you must change it to align with this requirement.
At the moment, Zondax is collaborating with Zingolabs and Zashi to add support for the app. Even though the integration is not completed, you can check how the approach was there for Keystore abstraction and LedgerKeystore component.
This functionality must be centralized as well by the Keystore component. The reason is that as mentioned in the previous sections, private keys must not be kept in memory as the ledger application won't let them be moved out of the device. Because of this strong requirement, both keystore implementations must align in this regard. This implies that the common interface would provide a method for revealing/signing data using the private keys. For example in our ZecWallet integration, the Keystore integration provides methods for creating node commitments, signing transactions, and many more that require the usage of private keys.
You can see how we check for the current Keystore variant being used, and call the corresponding handler. It is important to mention that in the zecwallet integration, only one instance could be used at the time.
It is relevant to note that the ledger keystore component internally uses the ZcashApp abstraction provided by our ledger-zcash-rs library. The ZcashApp component provides a defined set of methods that at the moment we consider sufficient for transparent and sapling operations within zcash protocol. This means that the Orchard and unified addresses protocols are not supported yet. In the following section, we will describe some of the supported operations this component provides and how to use it for establishing communication with the device. A further list of available methods can be found in the source code here.
Before you can start sending commands to the app, you need to open the communication channel. This can be done using Ledger transport. This is just a generic interface for communicating with a Ledger hardware device. There are different kinds of transports based on the technology (channels like U2F, HID, Bluetooth, Webusb) and environment (Node, Web,...)
So.. let’s start with simple commands like or since they don’t need any additional parameters.
You can check some tests that will be really helpful examples:
Here you can see the rest of the examples for both Rust and Javascript.
To get the transparent address from your device, you’ll need the command . It will need a derivation path. Keep in mind that this is an asynchronous operation and it might fail. This command and any other that doesn’t share sensitive information can be retrieved without explicit user confirmation.
Showing the address on the device is a really important confirmation step that the user needs to do before sharing an address. It would be good to add a button or some UI element to allow the user to verify that the wallet and the device show the same address.
Within the Sapling upgrade in Zcash, there are several types of keys, each serving different purposes. These keys can be categorized into private and public keys:
Spending key: this would be like your private key and therefore will never be moved out of the device. Any operation that uses this key will be carried out within the device.
Viewing keys: even though these can be considered public keys, since they can be used to disclose sensitive information, they will need an explicit approval from the user to be shared with the wallet or any other party.
Nullifiers: in order to prevent double-spending, Zcash relies on nullifiers that are revealed and recorded in the blockchain when the tokens are spent. These will be needed by the wallets to keep the right balance from your account. Once again, an explicit approval from the user is necessary here.
Payment addresses: these addresses are are inherently public since the user creates them to shared with someone in order to get a payment. Having one of these addresses doesn't reveal the movements from any other payment address or any of the keys.
The Ledger application provides functionalities for retrieving Sapling public keys and addresses. Bellow a short example of the provided API in rust to get the incomming viewing key (IVK):
And the next code block demostrates how to use the ZcashApp interface for getting a shielded address from the device:
The device, as mentioned previously, features a limited UI that enables the review of transaction fields and relevant data. The user is required to confirm the accuracy of this data and approve the operation. This verification and approval process will be conducted by the user each time sensitive information needs to leave the device.
This is one of the most important command that our communication interface provides. The overall idea is that the transaction data is sent serialized to the devices, users would them have to review the transaction and upon user confirmation, it would be signed. The returned data to the wallet would contain the signature. This is the general idea but to integrate the Zcash transaction signing feature of our Ledger application into your wallet, it's crucial to understand that the signing process is not straightforward, but rather interactive and step-by-step due to the cryptographic complexities involved, and the limited resources in terms of storage, memory and computing power from Ledger devices. Below you can see an overview of the process:
Initialization: The process begins with gathering transaction input data, including transparent and shielded inputs and outputs. This would depend of the kind of transaction:
transparent->shielded
transparent->transparent
shielded->transparent
shielded->shielded transactions
Building the Transaction:
Transparent Inputs: Add transparent inputs to the transaction builder without needing fresh information from the Ledger. This step requires the public key and outpoint from the blockchain.
Shielded Spends: For each shielded spend, the Ledger device provides the proof generation key, value commitment randomness (), and randomness for the random verification key (). This data is added to the transaction builder.
Shielded Outputs: Similar to shielded spends, adding shielded outputs requires randomness for the value commitment (), note commitment (), and random encryption key (), provided by the Ledger. This step is repeated for each shielded output.
Finalizing the Transaction: Once all inputs and outputs are added, the transaction builder compiles the transaction, including Zero-Knowledge (ZK) proofs. This compiled transaction data () is then sent back to the Ledger for validation and signing.
Extracting Signatures: The final step involves extracting signatures for both shielded spends and any transparent inputs from the Ledger. These signatures are then added to the transaction builder.
Completion: With all signatures in place, the transaction builder finalizes the transaction, making it ready for broadcast to the Zcash network.
This interactive process ensures the security and integrity of the transaction by leveraging the Ledger's cryptographic capabilities. It's essential for wallet developers to implement this step-by-step approach to integrate Zcash transaction signing functionality successfully. For further details, you can look at our transaction builder component written in Rust, and some tests on how it is used to build a transactions. If you are integrating this Ledger application in , you can take a look at our tests that provides a good insight on how perform this interactive process.
The communication package is completely decoupled from any type used on ZecWallet or Zcash ecosystem. Therefore, it should fit well on any wallet or integration that wants to use it. This includes both Rust and Javascript/Typescript packages.
The best place to find documentation about the app is located alongside with the app source code. You can find a mermaid diagram where the whole integration flow is explained clearly here. Besides, the APDU specification describes what each instruction is meant for, as well as expected input and output.
The app counts with a wide set of test cases. Each of them is meant to verify a certain feature or instruction works as expected. They are extremely useful as a reference for full integration. You can find them here. Moreover, if you want to see how the review process in the ledger device would look like, you can check this folder. There are snapshots for each test case that is executed on CI using an emulator, called speculous.
At the moment, there are some features that are not supported by the application and have to be considered when you plan to integrate this app in your wallet.
Due to the very limited resources from the device, the application can handle up to 5 transparent and 5 shielded inputs/outputs. If your transaction involves too many inputs/outputs, the device might not be able to handle it and it will be rejected every time.
At the moment, these values are fixed. So a transaction with 6 transparent inputs cannot be processed but a transaction with 5 transparent inputs, 5 shielded inputs, 5 transparent outputs and 5 shielded output would work just fine.
After the activation from Network Upgrade 5 (NU5), the default address type is the Unified Address (UA). At the moment, the app is not able to generate these types of addresses, so you'll need to consider this while making the integration.
Orchard protocol is not supported yet by the application. Consider that the application can only process Sapling transactions and you might need to adapt the wallet for it
The zcash tools package is highly coupled with types that were used by ZecWallet. They are outdated, according to the latest version for zcash crates. As it is today, they are useful for implementation references for any wallet to incorporate support to the ledger app.
Read More
Brussels Takes Center Stage: Key Highlights from EthCC, Polkadot Decoded, and More
Brussels hosted key Web3 events, highlighting progress in UX, AI integration, and blockchain innovations from Polkadot Decoded and Fil Brussels, aiming for a user-friendly Web3 future.
Cosmos Rosetta Dockerization: Simplifying Deployment and Enhancing Accessibility
The Rosetta project, amidst blockchain's complexity, emphasizes simplicity and accessibility. Docker integration underscores this commitment, empowering users and developers alike. Rosetta, now a plug-and-play solution, paves the way for seamless blockchain innovation.
Looking ahead: Integrating Rosetta with Cosmos SDK v0.50
"At Zondax, we're dedicated to innovation in the ever-evolving blockchain space. Our latest move is with Cosmos SDK v0.50.0-beta.0, offering Rosetta users an enhanced, seamless experience."
Other Articles
July 18, 2024
Brussels hosted key Web3 events, highlighting progress in UX, AI integration, and blockchain innovations from Polkadot Decoded and Fil Brussels, aiming for a user-friendly Web3 future.
News
March 6, 2024
The new Polkadot Ledger app is designed to easily manage different parts of the Polkadot network, like parachains and relay chain, even when there are updates. It was made as a result of community requests, and it brings together control of the network into one easy-to-use app. It's made to add new features without losing security. We found out that to make something really secure, we had to make changes on the node. Several alternatives were analyzed and each has advantages and disadvantages.
Protocol
April 9, 2024
Sign Mode Textual introduces a secure, user-friendly method for transaction signing with hardware devices, advancing efficiency and security in the Cosmos SDK.
News
The new Polkadot Ledger app is designed to easily manage different parts of the Polkadot network, like parachains and relay chain, even when there are updates. It was made as a result of community requests, and it brings together control of the network into one easy-to-use app. It's made to add new features without losing security. We found out that to make something really secure, we had to make changes on the node. Several alternatives were analyzed and each has advantages and disadvantages.
Protocol
Sign Mode Textual introduces a secure, user-friendly method for transaction signing with hardware devices, advancing efficiency and security in the Cosmos SDK.
© 2024 Zondax. All rights reserved.