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

Off-chain Messages #22

Merged
merged 9 commits into from
Nov 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 279 additions & 0 deletions cips/cip-X.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
---
cip: <to be assigned>
title: Off-chain Messages Signing
author: @JulianToledano
status: Draft
type: Standards Track
created: 2023-10-10
---

## Simple Summary

This is a convention for signing arbitrary messages. We propose this specification as a method for signing and
verifying off-chain arbitrary messages.

## Abstract

This CIP addresses the need for arbitrary message signing. These messages can be used for application sign-in by
providing proof of wallet ownership, but their use is not limited to this case. They can also be utilized for signing
files, text, and more.

There is no requirement for these messages to be posted to the network. That's why a set of off-chain messages is
defined with specific characteristics that prevent them from being processed as on-chain transactions.

This CIP defines two different messages. The first one allows users to sign any arbitrary data, including files, text,
objects, and more. The second one provides a way for application sign-in by defining a standard human-readable message
format that is parameterized by scope, session details, and security mechanisms.

## Motivation

Having the ability to sign messages off-chain has proven to be a fundamental aspect of nearly any blockchain.
The notion of signing messages off-chain has many added benefits, such as smart accounts where off-chain signing allows
for application layer authorizations saving on computational costs and reducing transaction throughput and overhead.
Within the context of the Cosmos ecosystem, some of the major applications of signing such data include, but are not
limited to, providing a cryptographically secure and verifiable means of proving validator identity and possibly
associating it with some other framework or organization. Additionally, having the ability to sign Cosmos messages
with a Ledger or similar HSM device.

## Documentation

This CIP introduces the concept of off-chain messages. Off-chain messages are messages that are not and cannot be
submitted to the network.

It opens the door to sign-in in dApps and webs and signing of files, text and objects.

Command-line applications will allow users to sign and verify files with commands like:

+ `simd keys sign [file] --from [key_name] > signed_file.json`
+ `simd keys verify [file]`


Websites and applications will be able to prove account ownership with a human-readable message instead of a random challenge.
An example format might look like this:

```
Prove account ownership to
https://myApp.com

"appDomain": "myApp",
"uri": "https://myApp.com/",
"signerAddress": "cosmos1hftz5ugqmpg9243xeegsqqav62f8hnywsjr4xr",
"nonce": "14368412",
"issued-at": "2023-10-10T10:10:10Z"
```

This approach is an improvement over the current state, as it allows for the signing of arbitrary data like files and
offers a more user-friendly sign-in process, replacing non-human-readable random challenges.

## Specification

Off-chain signed messages should resemble Cosmos SDK transactions but **must not** constitute a valid on-chain transaction.
`chain-id`, `account_number`, and `sequence` must all be assigned invalid values.

An off-chain transaction follows these rules:
JulianToledano marked this conversation as resolved.
Show resolved Hide resolved

+ the memo must be empty
+ nonce, sequence number must be equal to 0
+ chain-id must be equal to “”
JulianToledano marked this conversation as resolved.
Show resolved Hide resolved
+ fee gas must be equal to 0
+ fee amount must be an empty array
JulianToledano marked this conversation as resolved.
Show resolved Hide resolved

Verification of an off-chain transaction follows the same rules as an on-chain one, except for the specification
differences highlighted above.

As messages in Cosmos are defined as proto definitions, different messages can be defined for different off-chain
use cases, such as Sign-In, proof of wallet ownership or the ability to sign arbitrary data.

All off-chain messages will be of the type `offchain/messageKind`.

### MsgSignArbitraryData
JulianToledano marked this conversation as resolved.
Show resolved Hide resolved

The first message added to the `offchain` package is `MsgSignArbitraryData`.

`MsgSignArbitraryData` enables developers to sign arbitrary bytes that are valid only in an off-chain context. Here,
`AppDomain` represents the application requesting off-chain message signing, while `signerAddress` is the account address of
the signer. `Data` consists of a string with valid UTF-8 text that can represent various forms of data, including text, files, or
objects. The decision on how to deserialize, serialize, and interpret `Data` is left to the application developers,
depending on their specific use case. It is important to note that some signers are not capable of signing
arbitrary-length messages.

Application developers have the discretion to determine how `Data` should be handled. This includes defining the
serialization and deserialization processes and specifying the object that Data represents within their context.

Proto definition:

```protobuf
// MsgSignArbitraryData defines an arbitrary, general-purpose, off-chain message
message MsgSignArbitraryData {
option (cosmos.msg.v1.signer) = "signerAddress";
// AppDomain is the application requesting off-chain message signing
string appDomain = 1;
// Signer is the sdk.AccAddress of the message signer
string signerAddress = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Data represents the raw bytes of the content that is signed (text, json, etc)
string data = 3 [(gogoproto.jsontag) = "data"];
}
```

Signed MsgSignArbitraryData json example:

```json
{
"type": "cosmos-sdk/StdTx",
"value": {
"msg": [
{
"type": "offchain/MsgSignArbitraryData",
"value": {
"appDomain": "simd",
"signerAddress": "cosmos1hftz5ugqmpg9243xeegsqqav62f8hnywsjr4xr",
"data": "cmFuZG9t"
}
}
],
"fee": {
"amount": [],
"gas": "0"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "AqnDSiRoFmTPfq97xxEb2VkQ/Hm28cPsqsZm9jEVsYK9"
},
"signature": "8y8i34qJakkjse9pOD2De+dnlc4KvFgh0wQpes4eydN66D9kv7cmCEouRrkka9tlW9cAkIL52ErB+6ye7X5aEg=="
}
],
"memo": ""
}
}
```

### MsgProveIdentity

The second message added to the `offchain` package is `MsgProveIdentity`.

`MsgProveIdentity` enables the proof of wallet ownership for applications sign-in. In this context, `AppDomain` is the
application requesting off-chain message signing. `URI` refers to the resource that is the subject of the signing.
`signerAddress` is the account address of the signer. `Nonce` is a random string typically chosen by the relying on party and
used to prevent replay attacks. `Issued-at` the time when the message was generated.

Proto definition:

```protobuf
// MsgProveIdentity defines an arbitrary, general-purpose, off-chain message
message MsgProveIdentity {
option (cosmos.msg.v1.signer) = "signerAddress";
// AppDomain is the application requesting off-chain message signing
string appDomain = 1;
// Uri is the resource that is the subject of the signing
string uri = 2;
// Signer is the sdk.AccAddress of the message signer
string signerAddress = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// Nonce is a random string
string nonce = 4;
// Issued-at is the time when the message was generated
google.protobuf.Timestamp issued-at = 5;
}
```

Signed MsgProveIdentity JSON example:

```json
{
"type": "cosmos-sdk/StdTx",
"value": {
"msg": [
{
"type": "offchain/MsgProveIdentity",
"value": {
"appDomain": "exampleSwap",
"uri": "https://exampleSwap.com/login",
"signerAddress": "cosmos1hftz5ugqmpg9243xeegsqqav62f8hnywsjr4xr",
"nonce": "14368412",
"issued-at": "2023-10-10T16:25:24Z"
}
}
],
"fee": {
"amount": [],
"gas": "0"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "AqnDSiRoFmTPfq97xxEb2VkQ/Hm28cPsqsZm9jEVsYK9"
},
"signature": "8y8i34qJakkjse9pOD2De+dnlc4KvFgh0wQpes4eydN66D9kv7cmCEouRrkka9tlW9cAkIL52ErB+6ye7X5aEg=="
}
],
"memo": ""
}
}
```

## Drawbacks

This CIP requires a fixed relationship between an account address and a public key. That means it won't work if [ADR-034](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-rc.1/docs/architecture/adr-034-account-rekeying.md)
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
is implemented. This is because we cannot assume that `Address = Hash(PubKey)` anymore. This is not problematic for
everything that needs to be verified on-chain, but it is for off-chain. If a signer has changed its public key, how can
that be verified off-chain? Even if the message is enriched with a `chain-id` field, who is responsible for matching
`chain-id` and the node's IP?

It'd work with current multisigs as they are deterministic but on chain multisigs would not work here.

## Rationale

By creating different messages for different use cases, this design fulfills the current demands of the community for
[arbitrary data signing](https://github.com/cosmos/cosmos-sdk/issues/4581) and [human-readable sign-in message](https://github.com/cosmos/cosmos-sdk/pull/7896#issuecomment-1125254734).

Implementing this design aligns with the long-standing requests from the community. Several zones have implemented their
own arbitrary messages based on ADR-036:

+ [Sommelier](https://github.com/cosmos/cosmos-sdk/pull/7727#issuecomment-821201911)
+ [Aleph.im](https://github.com/cosmos/cosmos-sdk/pull/7727#issuecomment-821776061)
+ [Secret](https://github.com/scrtlabs/cosmos-sdk/compare/v0.9.1-scrt...v0.9.2-scrt)

Even some work have been done on [cosmjs](https://github.com/cosmos/cosmjs/pull/847).

There are zones and applications that prove account ownership by signing a random challenge with ADR-036 specification.

## Prior Art

Other blockchains such as Ethereum with [eip-4361](https://eips.ethereum.org/EIPS/eip-4361) or Solana with its
[Off-chain message signing](https://docs.solana.com/proposals/off-chain-message-signing) offer standard methods for
application sign-in.

There was a prior attempt to implement this in the sdk with [ADR-036](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-rc.1/docs/architecture/adr-036-arbitrary-signature.md).
However, a consensus was not achieved on ADR-036, as the community demanded a way for sign-in method that ADR-036
did not provide. This is the main reason for defining two different messages in this CIP. One for arbitrary data and
the other for sing-in.


## Unresolved Questions

+ Is defining different messages per use case the best approach, or could a protobuf with a `oneof` be sufficient?
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
+ Should `Data` in `MsgSignArbitraryData` have a max length?
JulianToledano marked this conversation as resolved.
Show resolved Hide resolved

## Backwards Compatibility

Backwards compatibility is guaranteed as this CIP introduces new messages but does not modify any prior work. Although
it won't be compatible with ADR-036 as it defines different messages.

## Security Considerations

It is important to notice that the `Data` field in `MsgSignArbitraryData` consists of a valid UTF-8 string, this does
not mean that the string is printable or that the signing device would be capable of printing it. Examples of such valid
strings are NULL, [BELL](https://en.wikipedia.org/wiki/Bell_character), emojis or unicode in the
[Private Use Areas](https://en.wikipedia.org/wiki/Private_Use_Areas).

There are no more security considerations as the messages will not be on-chain.

## Future Possibilities

This opens the possibility to create new off-chain messages for future use cases.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Loading