Skip to content

Potentially dangerous sign_msg function should be removed #90

@MarvinJanssen

Description

@MarvinJanssen

The potentially dangerous sign_msg function introduced in #82 should be removed. It is based on Ethereum's personal_sign, the use of which is discouraged since the introduction of the much superior EIP712 standard. EIP712 addresses the many issues and shortcomings of personal_sign. If the function is adopted in Stacks wallets, it will put the entire ecosystem on a perilous path. We should learn from the Ethereum space and skip this function completely.

personal_sign had two main use cases:

  1. Signing messages to authenticate with some app/dapp.
  2. Signing messages that authorise some on-chain action.

When it comes to the first, we already have an authentication scheme. Right now it does not allow us to prove address ownership, but that can be achieved in different ways. (I will come back to this at the end.)

The second one is more important, so I will focus on that. Signed messages have been used for many different things in the Ethereum space. I will take on one such example for brevity: off-chain order signing. 0xProtocol allows users to sign an order, which can later be submitted to a smart contract to make a token trade happen. Early versions of the protocol would hash an order structure and request users to sign the order hash via personal_sign to authorise the trade.

It first looked like this:

image

And then this:

image

Does the user have any idea what he or she is actually signing? Obviously not. The user will just have to trust that the dapp fed the right message to the wallet. The messages are also not domain specific, which means that a malicious app could trick a user into signing something meant for another platform. And since the messages that are passed to the wallet are hashes, there is no way to reconstruct the original message in the wallet. It is just all-round terrible UX and highly dangerous. In hindsight it is obvious that the function should never have existed, but back then it is all we had and such signed messages were cutting edge. They allowed for many new an exciting things. Although personal_sign was largely left behind, it is still causing longer-lasting damage because it normalised the concept of signing byte strings. Many people are now so used to signing on-chain actions in this way, that they just hit Confirm when that wallet screen pops up. The sign_msg function opens us up to all of it.

Signing byte strings should not be normalised in the Stacks ecosystem.

I cannot stress that enough. We have so many tools at our disposal to make the UX a lot better and safer. Ethereum did not have the benefit of a human-readable interpreted language like Clarity. There is no good reason to introduce a personal_sign equivalent for Stacks.

Besides, it seems to be carelessly implemented and actually commits the same mistake as the original personal_sign implementation.

https://github.com/Zondax/ledger-blockstack/blob/abaf1d01a0bef27b2a603ec3d15bb6a20ddbcc96/js/src/index.ts#L245

  • The \x19 is a (Bitcoin) varint representing the byte length of the prefix, which is correct for Ethereum Signed Message:\n as it's 25, but not for Stacks Signed Message:\n. It seems like it was copy and pasted thoughtlessly. It should have been \x18.
  • The message length is appended as an ASCII string, so you have no idea where the actual message starts. They made the same mistake in geth. Sign message is using incorrect prefix ethereum/go-ethereum#14794

The language in #76 almost makes it sound like sign_msg is a stopgap solution until we have something better. I really do not think that is the right approach. I rather have nothing, over this function, until a good message signing standard arrives. Hiro, as a shepherd of the Stacks ecosystem, should consider very carefully whether adding such a function is worth it.

There is a draft SIP that describes a structured data signing method much like EIP712. It describes a general structured message signing standard that leverages Stacks wire format, while still allowing safe human-readable text message signing. (If people insist.) I would welcome such a standard or one like it. And to go back to proving address ownership, the linked SIP would make that effortless as well.

I hope that all this is convincing enough to remove sign_msg. For reference, we are building a hardware wallet at Ryder and will not implement an unstructured message signing function such as this one for the reasons laid out above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions