Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CIP-0021 | Restrictions on transactions signed by hardware wallets #107

Merged
merged 5 commits into from
Sep 15, 2021
115 changes: 115 additions & 0 deletions CIP-0021/CIP-0021.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
CIP: 0021
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

21 (tentative)

Title: Restrictions on transactions signed by hardware wallets
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the title is a bit misleading. Rather this CIP wants to establish some best practices for HW wallets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the intention is unclear and should be made clearer in the CIP. It does not comment on best practices, but lists limitations arising from hardware limitations of Trezor and especially Ledger.

The intended CIP audience are people integrating with HW wallets (developers of software wallets and similar tools), not HW wallet developers. In other words the CIP should define how you should build your transactions in order for them to be compatible (signable) with HW wallets - specifically Ledger and Trezor (not sure if there are other significant ones currently). In general, the rules should be a superset of restrictions for each HW wallet, so if you follow this CIP, you would be compatible with all HW wallets, and if you don't, you risk that some parties use HW wallets and will not be able to sign your transaction. This is especially important in context of transactions signed by multiple parties.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest using the term "interoperability" in the title, e.g. "Transaction guidelines for interoperability with hardware wallets".

Authors: Gabriel Kerekes <gabriel.kerekes@vacuumlabs.com>, Rafael Korbas <rafael.korbas@vacuumlabs.com>, Jan Mazak <jan.mazak@vacuumlabs.com>
Status: Draft
Type: Standards
Created: 2021-06-15
License: CC-BY-4.0
---

## Abstract

This CIP describes all the restrictions applicable to Cardano transactions which need to be signed by hardware wallets.

## Motivation

Due to certain limitations of HW wallets, especially very small memory and a limited set of data types supported by Ledger, HW wallets are not able to process all valid transactions which are supported by Cardano nodes.
KtorZ marked this conversation as resolved.
Show resolved Hide resolved

The limitations also result in an inability of HW wallets to see the whole transaction at once. Transaction data are streamed into HW wallets in small chunks and they compute a rolling hash of the transaction body which is signed at the end. Consequently, a HW wallet only provides witness signatures, and the transaction body which was signed has to be reconstructed by the client. We thus need a common transaction serialization format which will allow no ambiguity. In addition, the format must define ordering of map keys in such a way that it’s possible to check for duplicate keys by HW wallets.

Several of the restrictions also stem from security or UX concerns, e.g. the forbidden combination of pool registration certificates and withdrawals in a single transaction (see reasoning below).

To ensure interoperability, SW wallets and other tools working with HW wallets should only use transactions which conform to the following rules.

## Specification

### Canonical CBOR serialization format

Transactions must be serialized in line with suggestions from [Section 3.9 of CBOR specification RFC](https://datatracker.ietf.org/doc/html/rfc7049#section-3.9). In particular:

- Integers must be as small as possible.
- The expression of lengths in major types 2 through 5 must be as short as possible.
- The keys in every map must be sorted from lowest value to highest.
- Indefinite-length items must be made into definite-length items.

See the RFC for details.
KtorZ marked this conversation as resolved.
Show resolved Hide resolved

### Transaction body

Full support for some elements is not implemented yet (especially those related to scripts), but that is likely to change in the near future. The following restrictions are, however, unlikely to ever be lifted.

**Unsupported entries**

The transaction body entry `6 : update` must not be included.
KtorZ marked this conversation as resolved.
Show resolved Hide resolved

**Integers**

While the Cardano CDDL specification usually does not limit the size of integers, HW wallets only support `int64` for signed integers and `uint64` for unsigned integers. Any integer value must fit in the appropriate type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alas... I am still not sure whether unbounded integers on the blockchain was a good idea in the first place 😶

Copy link
Contributor

@dcoutts dcoutts Aug 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do limit the size in the CDDL, usually to signed or unsigned int 64. There are only a few places where we allow "big ints". See the big_int type definition in the Alonzo CDDL.

And note that those big ints are themselves bounded to 64 bytes. This is for Plutus integer data.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And note that those big ints are themselves bounded to 64 bytes.

That's good to know actually.


**Numbers of transaction elements**

The numbers of inputs, outputs, certificates, withdrawals, tokens in an asset group, and other similar transaction elements must not exceed `UINT16_MAX`, i.e. 65535.
KtorZ marked this conversation as resolved.
Show resolved Hide resolved

**Multiassets**

Since multiassets (`policy_id` and `asset_name`) are represented as maps, both need to be sorted in accordance with the specified canonical CBOR format. Also, an output or the mint field must not contain duplicate `policy_id`s and a policy must not contain duplicate `asset_name`s.

**Certificates**

Certificates of type `genesis_key_delegation` and `move_instantaneous_rewards_cert` are not supported and must not be included.

If a transaction contains a pool registration certificate, then it must not contain:

- any other certificate;
- any withdrawal;
- mint entry.

It is allowed to arbitrarily combine other supported certificate types, but all the certificates included in a transaction must have the same type of stake credential i.e. either 0 - `addr_keyhash` or 1 - `scripthash`. The stake credential type must also be consistent with the type used for withdrawals.

**Withdrawals**

Since withdrawals are represented as a map of reward accounts, withdrawals also need to be sorted in accordance with the specified canonical CBOR format. A transaction must not contain duplicate withdrawals. All withdrawals included in a transaction must have the same type of stake credential i.e. either 0 - `addr_keyhash` or 1 - `scripthash`. The stake credential type must also be consistent with the type used for certificates.

### Transaction witnesses

There are two limits on the number of witnesses:

- an absolute limit of `UINT16_MAX`, i.e. 65535;
- a relative limit dependent on the transaction body (essentially one witness per each input, each withdrawal and each certificate in a typical transaction).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This second condition may be overly restrictive in Alonzo where it'll be allowed to request additional signatures which do not correspond to any input. This would be however specified by a dedicated field on transactions required_signers (key 14 in transaction body).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change with the introduction of multi-sig to HW wallets which is currently being finalised. It will be possible to send additional_witness_requests to the HW wallets which will sign the transaction with a key derived from the path given in the request.


## Reasoning

### Canonical CBOR serialization format

As HW wallets don't return the whole serialized transaction, a common CBOR serialization is needed so that software wallets and other tools interacting with HW wallets are be able to deterministically reproduce the transaction body built and signed by the HW wallet.

The specified canonical CBOR format is consistent with how certain other data are serialized (e.g. Plutus script data in Alonzo) and allows the use of standard CBOR libraries out of the box.

### Transaction body

**Multiassets**

Allowing duplicate `policy_id`s (or `asset_name`s) might lead to inconsistencies between what is displayed to the user and how nodes and other tools might interpret the duplicate keys, i.e. all policies (or asset names) would be shown to the user, but nodes and other tools might eventually interpret only a single one of them.

**Certificates**

Combining withdrawals and pool registration certificates isn't allowed because both are signed by staking keys by pool owners. If it was allowed to have both in a transaction then the witness provided by a pool owner might inadvertently serve as a witness for a withdrawal for the owner's account.

**Withdrawals**

Similarly to multiassets, allowing duplicate withdrawals might lead to inconsistencies between what is displayed to the user and how nodes and other tools might interpret the duplicate keys.

### Transaction witnesses

The relative limit is imposed to avoid leaking signatures the user is not aware of - for ordinary transactions, witnesses are not shown. It does not apply to script witnesses which are always shown on the screen.

However, since a HW wallet only deals with the transaction body and not the whole transaction, it is possible to make several calls to a HW wallet and collect more witnesses than these limits allow (the user has to click through the transaction more than once in such a case).

## Backwards compatibility

Most of the restrictions are already implemented in HW wallets except the canonical CBOR serialization. Tools interacting with HW wallets might need to be updated in order to continue being compatible with HW wallets when the canonical CBOR serialization format is enforced in HW wallets.

## Copyright

This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode)