ADR 015: Crypto encoding

Context

We must standardize our method for encoding public keys and signatures on chain. Currently we amino encode the public keys and signatures. The reason we are using amino here is primarily due to ease of support in parsing for other languages. We don’t need its upgradability properties in cryptosystems, as a change in the crypto that requires adapting the encoding, likely warrants being deemed a new cryptosystem. (I.e. using new public parameters)

Decision

Public keys

For public keys, we will continue to use amino encoding on the canonical representation of the pubkey. (Canonical as defined by the cryptosystem itself) This has two significant drawbacks. Amino encoding is less space-efficient, due to requiring support for upgradability. Amino encoding support requires forking protobuf and adding this new interface support option in the langauge of choice.

The reason for continuing to use amino however is that people can create code more easily in languages that already have an up to date amino library. It is possible that this will change in the future, if it is deemed that requiring amino for interacting with tendermint cryptography is unneccessary.

The arguments for space efficiency here are refuted on the basis that there are far more egregious wastages of space in the SDK. The space requirement of the public keys doesn’t cause many problems beyond increasing the space attached to each validator / account.

The alternative to using amino here would be for us to create an enum type. Switching to just an enum type is worthy of investigation post-launch. For referrence, part of amino encoding interfaces is basically a 4 byte enum type definition. Enum types would just change that 4 bytes to be a varuint, and it would remove the protobuf overhead, but it would be hard to integrate into the existing API.

Signatures

Signatures should be switched to be []byte. Spatial efficiency in the signatures is quite important, as it directly affects the gas cost of every transaction, and the throughput of the chain. Signatures don’t need to encode what type they are for (unlike public keys) since public keys must already be known. Therefore we can validate the signature without needing to encode its type.

When placed in state, signatures will still be amino encoded, but it will be the primitive type []byte getting encoded.

Ed25519

Use the canonical representation for signatures.

Secp256k1

There isn’t a clear canonical representation here. Signatures have two elements r,s. These bytes are encoded as r || s, where r and s are both exactly 32 bytes long, encoded big-endian. This is basically Ethereum’s encoding, but without the leading recovery bit.

Status

Implemented

Consequences

Positive

  • More space efficient signatures

Negative

  • We have an amino dependency for cryptography.

Neutral

  • No change to public keys