The purpose of this EIP is to provide a process and data transmission protocol via QR Code between offline signers and watch-only wallets.
Motivation
There is an increasing number of users whom like to use complete offline signers to manage their private keys, signers like hardware wallets and mobile phones in offline mode. In order to sign transactions or data, these offline signers have to rely on a watch-only wallet since it would prepare the data to be signed. Currently, there are 4 possible data transmission methods between offline signers and watch-only wallets: QR Code, USB, Bluetooth, and file transfer. The QR Code data transmission method have the following advantages when compared to the other three methods mentioned above:
Transparency and Security: Compared to USB or Bluetooth, users can easily decode the data via QR Code (with the help of some tools). It can also help users clearly identify what they are going to sign, which improves transparency and thus better security.
Improved Compatibility: Compared to USB and Bluetooth, QR Code data transmissions has a wider range of compatibility. Normally, it wouldn’t be broken by software changes like browser upgrades, system upgrade, and etc.
Improved User experience: QR Code data transmissions can provide a better user experience compared to USB, Bluetooth, and file transfer especially when the user is using a mobile device.
A smaller attack surface: USB and Bluetooth have a bigger attack surface than QR-Codes.
Due to these advantages, QR Code data transmissions is a better choice. Unfortunately, there is no modern standard for how offline signers should work with watch-only wallets nor how data should be encoded.
This EIP presents a standard process and data transmission protocol for offline signers to work with watch-only wallets.
Specification
Offline signer: An offline signer is a device or application which holds the user’s private keys and does not have network access.
Watch-only wallet: A watch-only wallet is a wallet that has network access and can interact with the Ethereum blockchain.
Process
In order to work with offline signers, the watch-only wallet should follow the following process.
The offline signer provides the public key information to the watch-only wallet to generate addresses, sync balances and etc via QR Codes.
The watch-only wallet generates the unsigned data and sends it to an offline signer for signing via QR Code, data that can include transactions, typed data, and etc.
The offline signer signs the data and provides a signature back to the watch-only wallet via QR Code.
The watch-only wallet receives the signature, constructs the signed data (transaction) and performs the following activities like broadcasting the transaction etc.
Data Transmission Protocol
Since a single QR Code can only contain a limited amount of data, animated QR Codes should be utilized for data transmission. The BlockchainCommons have published a series of data transmission protocol called Uniform Resources (UR). It provides a basic method to encode data into animated QR Codes. This EIP will use UR and extend its current definition.
Concise Binary Object Representation(CBOR) will be used for binary data encoding. Concise Data Definition Language(CDDL) will be used for expressing the CBOR.
Setting up the watch-only wallet with the offline signer
In order to allow a watch-only wallet to collect information from the Ethereum blockchain, the offline signer would need to provide the public keys to the watch-only wallet in which the wallet will use them to query the necessary information from the Ethereum blockchain.
In such a case, offline signers should provide the extended public keys and derivation path. The UR Type called crypto-hdkey will be used to encode this data and the derivation path will be encoded as crypto-keypath.
CDDL for Key Path
The crypto-keypath will be used to specify the key path.The following specification is written in Concise Data Definition Language(CDDL) for crypto-key-path
; Metadata for the derivation path of a key.
;
; `source-fingerprint`, if present, is the fingerprint of the
; ancestor key from which the associated key was derived.
;
; If `components` is empty, then `source-fingerprint` MUST be a fingerprint of
; a master key.
;
; `depth`, if present, represents the number of derivation steps in
; the path of the associated key, even if not present in the `components` element
; of this structure.
crypto-keypath = {
components: [path-component], ; If empty, source-fingerprint MUST be present
? source-fingerprint: uint32 .ne 0 ; fingerprint of ancestor key, or master key if components is empty
? depth: uint8 ; 0 if this is a public key derived directly from a master key
}
path-component = (
child-index / child-index-range / child-index-wildcard-range,
is-hardened
)
uint32 = uint .size 4
uint31 = uint32 .lt 2147483648 ;0x80000000
child-index = uint31
child-index-range = [child-index, child-index] ; [low, high] where low < high
child-index-wildcard = []
is-hardened = bool
components = 1
source-fingerprint = 2
depth = 3
CDDL for Extended Public Keys
Since the purpose is to transfer public key data, the definition of crypto-hdkey will be kept only for public key usage purposes.
The following specification is written in Concise Data Definition Language CDDL and includes the crypto-keypath spec above.
; An hd-key must be a derived key.
hd-key = {
derived-key
}
; A derived key must be public, has an optional chain code, and
; may carry additional metadata about its use and derivation.
; To maintain isomorphism with [BIP32] and allow keys to be derived from
; this key `chain-code`, `origin`, and `parent-fingerprint` must be present.
; If `origin` contains only a single derivation step and also contains `source-fingerprint`,
; then `parent-fingerprint` MUST be identical to `source-fingerprint` or may be omitted.
derived-key = (
key-data: key-data-bytes,
? chain-code: chain-code-bytes ; omit if no further keys may be derived from this key
? origin: #6.304(crypto-keypath), ; How the key was derived
? name: text, ; A short name for this key.
? source: text, ; The device info or any other description for this key
)
key-data = 3
chain-code = 4
origin = 6
name = 9
source = 10
uint8 = uint .size 1
key-data-bytes = bytes .size 33
chain-code-bytes = bytes .size 32
If the chain-code is provided, then it can be used to derive child keys but if it isn’t provided, it is simply a solo key and the origin can be provided to indicate the derivation key path.
If the signer would like to provide muliple public keys instead of the extended public key for any reason, the signer can use crypto-account for that.
Sending the unsigned data from the watch-only wallet to the offline signer
To send the unsigned data from a watch-only wallet to an offline signer, the new UR type eth-sign-request will be introduced to encode the signing request.
CDDL for Eth Sign Request.
The following specification is written in Concise Data Definition Language CDDL.
UUIDs in this specification notated UUID are CBOR binary strings tagged with #6.37, per the IANA CBOR Tags Registry.
; Metadata for the signing request for Ethereum.
;
sign-data-type = {
type: int .default 1 transaction data; the unsigned data type
}
eth-transaction-data = 1; legacy transaction rlp encoding of unsigned transaction data
eth-typed-data = 2; EIP-712 typed signing data
eth-raw-bytes=3; for signing message usage, like EIP-191 personal_sign data
eth-typed-transaction=4; EIP-2718 typed transaction of unsigned transaction data
; Metadata for the signing request for Ethereum.
; request-id: the identifier for this signing request.
; sign-data: the unsigned data
; data-type: see sign-data-type definition
; chain-id: chain id definition see https://github.com/ethereum-lists/chains for detail
; derivation-path: the key path of the private key to sign the data
; address: Ethereum address of the signing type for verification purposes which is optional
eth-sign-request = (
sign-data: sign-data-bytes, ; sign-data is the data to be signed by offline signer, currently it can be unsigned transaction or typed data
data-type: #3.401(sign-data-type),
chain-id: int .default 1,
derivation-path: #5.304(crypto-keypath), ;the key path for signing this request
?request-id: uuid, ; the uuid for this signing request
?address: eth-address-bytes, ;verification purpose for the address of the signing key
?origin: text ;the origin of this sign request, like wallet name
)
request-id = 1
sign-data = 2
data-type = 3
chain-id = 4 ;it will be the chain id of ethereum related blockchain
derivation-path = 5
address = 6
origin = 7
eth-address-bytes = bytes .size 20
sign-data-bytes = bytes ; for unsigned transactions it will be the rlp encoding for unsigned transaction data and ERC 712 typed data it will be the bytes of json string.
The signature provided by offline signers to watch-only wallets
After the data is signed, the offline signer should send the signature back to the watch-only wallet. The new UR type called eth-signature is introduced here to encode this data.
CDDL for Eth Signature.
The following specification is written in Concise Data Definition Language CDDL.
eth-signature = (
request-id: uuid,
signature: eth-signature-bytes,
? origin: text, ; The device info for providing this signature
)
request-id = 1
signature = 2
origin = 3
eth-signature-bytes = bytes .size 65; the signature of the signing request (r,s,v)
Rationale
This EIP uses some existing UR types like crypto-keypath and crypto-hdkey and also introduces some new UR types like eth-sign-request and eth-signature. Here are the reasons we choose UR for the QR Code data transmission protocol:
UR provides a solid foundation for QR Code data transmission
Uses the alphanumeric QR code mode for efficiency.
Includes a CRC32 checksum of the entire message in each part to tie the different parts of the QR code together and ensure the transmitted message has been reconstructed.
uses Fountain Code for the arbitrary amount of data which can be both a minimal, finite sequence of parts and an indefinite sequence of parts. The Fountain Code can ultimately help the receiver to make the data extraction easier.
UR provides existing helpful types and scalability for new usages
Currently, UR has provided some existing types like crypto-keypath and crypto-hdkey so it is quite easy to add a new type and definitions for new usages.
UR has an active air-gapped wallet community.
Currently, the UR has an active airgapped wallet community which continues to improve the UR forward.
Backwards Compatibility
Currently, there is no existing protocol to define data transmissions via QR Codes so there are no backward compatibility issues that needs to be addressed now.
Test Cases
The test cases can be found on the ur-registry-eth package released by the Keystone team.
Reference Implementation
The reference implementation can be found on the ur-registry-eth package released by the Keystone team.
Security Considerations
The offline signer should decode all the data from eth-sign-request and show them to the user for confirmation prior to signing. It is recommended to provide an address field in the eth-sign-request. If provided, the offline signer should verify the address being the same one as the address associated with the signing key.
Aaron Chen (@aaronisme), Sora Lee (@soralit), ligi (@ligi), Dan Miller (@danjm), AndreasGassmann (@andreasgassmann), xardass (@xardass), Lixin Liu (@BitcoinLixin), "ERC-4527: QR Code transmission protocol for wallets [DRAFT]," Ethereum Improvement Proposals, no. 4527, December 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4527.