# Accounts

This document describes the in-built account and public key system of the Cosmos SDK.

# Pre-requisite Readings

# Account Definition

In the Cosmos SDK, an account designates a pair of public key PubKey and private key PrivKey. The PubKey can be derived to generate various Addresses, which are used to identify users (among other parties) in the application. Addresses are also associated with messages to identify the sender of the message. The PrivKey is used to generate digital signatures to prove that an Address associated with the PrivKey approved of a given message.

For HD key derivation the Cosmos SDK uses a standard called BIP32 (opens new window). The BIP32 allows users to create an HD wallet (as specified in BIP44 (opens new window)) - a set of accounts derived from an initial secret seed. A seed is usually created from a 12- or 24-word mnemonic. A single seed can derive any number of PrivKeys using a one-way cryptographic function. Then, a PubKey can be derived from the PrivKey. Naturally, the mnemonic is the most sensitive information, as private keys can always be re-generated if the mnemonic is preserved.

Copy Account 0 Account 1 Account 2 +------------------+ +------------------+ +------------------+ | | | | | | | Address 0 | | Address 1 | | Address 2 | | ^ | | ^ | | ^ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + | | + | | + | | Public key 0 | | Public key 1 | | Public key 2 | | ^ | | ^ | | ^ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + | | + | | + | | Private key 0 | | Private key 1 | | Private key 2 | | ^ | | ^ | | ^ | +------------------+ +------------------+ +------------------+ | | | | | | | | | +--------------------------------------------------------------------+ | | +---------+---------+ | | | Master PrivKey | | | +-------------------+ | | +---------+---------+ | | | Mnemonic (Seed) | | | +-------------------+

In the Cosmos SDK, keys are stored and managed by using an object called a Keyring.

# Keys, accounts, addresses, and signatures

The principal way of authenticating a user is done using digital signatures (opens new window). Users sign transactions using their own private key. Signature verification is done with the associated public key. For on-chain signature verification purposes, we store the public key in an Account object (alongside other data required for a proper transaction validation).

In the node, all data is stored using Protocol Buffers serialization.

The Cosmos SDK supports the following digital key schemes for creating digital signatures:

Address length in bytes Public key length in bytes Used for transaction authentication Used for consensus (tendermint)
secp256k1 20 33 yes no
secp256r1 32 33 yes no
tm-ed25519 -- not used -- 32 no yes

# Addresses

Addresses and PubKeys are both public information that identifies actors in the application. Account is used to store authentication information. The basic account implementation is provided by a BaseAccount object.

Each account is identified using Address which is a sequence of bytes derived from a public key. In SDK, we define 3 types of addresses that specify a context where an account is used:

  • AccAddress identifies users (the sender of a message).
  • ValAddress identifies validator operators.
  • ConsAddress identifies validator nodes that are participating in consensus. Validator nodes are derived using the ed25519 curve.

These types implement the Address interface:

Copy // Address is a common interface for different types of addresses used by the SDK type Address interface { Equals(Address) bool Empty() bool Marshal() ([]byte, error) MarshalJSON() ([]byte, error) Bytes() []byte String() string Format(s fmt.State, verb rune) } // Ensure that different address types implement the interface var _ Address = AccAddress{} var _ Address = ValAddress{} var _ Address = ConsAddress{} var _ yaml.Marshaler = AccAddress{} var _ yaml.Marshaler = ValAddress{} var _ yaml.Marshaler = ConsAddress{}

Address construction algorithm is defined in ADR-28 (opens new window). Here is the standard way to obtain an account address from a pub public key:

Copy sdk.AccAddress(pub.Address().Bytes())

Of note, the Marshal() and Bytes() method both return the same raw []byte form of the address. Marshal() is required for Protobuf compatibility.

For user interaction, addresses are formatted using Bech32 (opens new window) and implemented by the String method. The Bech32 method is the only supported format to use when interacting with a blockchain. The Bech32 human-readable part (Bech32 prefix) is used to denote an address type. Example:

Copy // String implements the Stringer interface. func (aa AccAddress) String() string { if aa.Empty() { return "" } bech32PrefixAccAddr := GetConfig().GetBech32AccountAddrPrefix() bech32Addr, err := bech32.ConvertAndEncode(bech32PrefixAccAddr, aa.Bytes()) if err != nil { panic(err) } return bech32Addr }

Address Bech32 Prefix
Accounts cosmos
Validator Operator cosmosvaloper
Consensus Nodes cosmosvalcons

# Public Keys

Public keys in Cosmos SDK are defined by cryptotypes.PubKey interface. Since public keys are saved in a store, cryptotypes.PubKey extends the proto.Message interface:

Copy // PubKey defines a public key and extends proto.Message. type PubKey interface { proto.Message Address() Address Bytes() []byte VerifySignature(msg []byte, sig []byte) bool Equals(PubKey) bool Type() string }

A compressed format is used for secp256k1 and secp256r1 serialization.

  • The first byte is a 0x02 byte if the y-coordinate is the lexicographically largest of the two associated with the x-coordinate.
  • Otherwise the first byte is a 0x03.

This prefix is followed by the x-coordinate.

Public Keys are not used to reference accounts (or users) and in general are not used when composing transaction messages (with few exceptions: MsgCreateValidator, Validator and Multisig messages). For user interactions, PubKey is formatted using Protobufs JSON (ProtoMarshalJSON (opens new window) function). Example:

Copy // NewKeyOutput creates a default KeyOutput instance without Mnemonic, Threshold and PubKeys func NewKeyOutput(name string, keyType KeyType, a sdk.Address, pk cryptotypes.PubKey) (KeyOutput, error) { // nolint:interfacer apk, err := codectypes.NewAnyWithValue(pk) if err != nil { return KeyOutput{}, err } bz, err := codec.ProtoMarshalJSON(apk, nil) if err != nil { return KeyOutput{}, err } return KeyOutput{ Name: name, Type: keyType.String(), Address: a.String(), PubKey: string(bz), }, nil }

# Keyring

A Keyring is an object that stores and manages accounts. In the Cosmos SDK, a Keyring implementation follows the Keyring interface:

Copy // Keyring exposes operations over a backend supported by github.com/99designs/keyring. type Keyring interface { // List all keys. List() ([]Info, error) // Supported signing algorithms for Keyring and Ledger respectively. SupportedAlgorithms() (SigningAlgoList, SigningAlgoList) // Key and KeyByAddress return keys by uid and address respectively. Key(uid string) (Info, error) KeyByAddress(address sdk.Address) (Info, error) // Delete and DeleteByAddress remove keys from the keyring. Delete(uid string) error DeleteByAddress(address sdk.Address) error // NewMnemonic generates a new mnemonic, derives a hierarchical deterministic // key from that, and persists it to the storage. Returns the generated mnemonic and the key // Info. It returns an error if it fails to generate a key for the given algo type, or if // another key is already stored under the same name. NewMnemonic(uid string, language Language, hdPath string, algo SignatureAlgo) (Info, string, error) // NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it. NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error) // SaveLedgerKey retrieves a public key reference from a Ledger device and persists it. SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) // SavePubKey stores a public key and returns the persisted Info structure. SavePubKey(uid string, pubkey types.PubKey, algo hd.PubKeyType) (Info, error) // SaveMultisig stores and returns a new multsig (offline) key reference. SaveMultisig(uid string, pubkey types.PubKey) (Info, error) Signer Importer Exporter }

The default implementation of Keyring comes from the third-party 99designs/keyring (opens new window) library.

A few notes on the Keyring methods:

  • Sign(uid string, payload []byte) ([]byte, sdkcrypto.PubKey, error) strictly deals with the signature of the payload bytes. You must prepare and encode the transaction into a canonical []byte form. Because protobuf is not deterministic, it has been decided in ADR-020 that the canonical payload to sign is the SignDoc struct, deterministically encoded using ADR-027. Note that signature verification is not implemented in the SDK by default, it is deferred to the anteHandler. Copy // SignDoc is the type used for generating sign bytes for SIGN_MODE_DIRECT. message SignDoc { // body_bytes is protobuf serialization of a TxBody that matches the // representation in TxRaw. bytes body_bytes = 1; // auth_info_bytes is a protobuf serialization of an AuthInfo that matches the // representation in TxRaw. bytes auth_info_bytes = 2; // chain_id is the unique identifier of the chain this transaction targets. // It prevents signed transactions from being used on another chain by an // attacker string chain_id = 3; // account_number is the account number of the account in state uint64 account_number = 4; }

  • NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SignatureAlgo) (Info, error) creates a new account based on the bip44 path (opens new window) and persists it on disk. The PrivKey is never stored unencrypted, instead it is encrypted with a passphrase (opens new window) before being persisted. In the context of this method, the key type and sequence number refer to the segment of the BIP44 derivation path (for example, 0, 1, 2, ...) that is used to derive a private and a public key from the mnemonic. Using the same mnemonic and derivation path, the same PrivKey, PubKey and Address is generated. The following keys are supported by the keyring:

  • secp256k1

  • ed25519

  • ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error) exports a private key in ASCII-armored encrypted format using the given passphrase. You can then either import the private key again into the keyring using the ImportPrivKey(uid, armor, passphrase string) function or decrypt it into a raw private key using the UnarmorDecryptPrivKey(armorStr string, passphrase string) function.

# Next

Learn about gas and fees