In this section you are going to learn all about accounts in Cosmos:
- What they are
- How they are stored
- Optional implementations
- Cryptography foundations
At the end of the section, you can see how the use of accounts can resolve a current problem for your checkers blockchain: how to ensure moves are only played by the appropriate player.
An account is a pair of keys:
PubKey: a public key
PrivKey: a private key
A public key is a unique identifier for a user or entity that is safe to disclose. Private keys are sensitive information that users are required to manage confidentially. Private keys are used to sign information in a way that proves to others that a message was signed by someone using the private key corresponding to a given public key. This is done without revealing the private key itself.
# Public key cryptography
Modern cryptographic systems leverage computer capabilities to make the power of certain mathematical functions accessible. Public key cryptography is also known as asymmetric cryptography and is a cryptographic system that employs pairs of keys. Every pair consists of a public and a private key. The security of the system is not endangered as long as the private key is not disclosed. Compared to symmetric key algorithms, asymmetric ones do not require parties to use a secure channel to exchange the keys for encryption and decryption.
Asymmetric cryptography has two primary applications:
This section focuses on the authentication aspect of asymmetric cryptography.
Asymmetric cryptography is normally applied to small data blocks due to its computational complexity. Symmetric and asymmetric cryptography can be combined in a hybrid system. For example, asymmetric encryption could be employed to transfer a symmetric encryption, then used as an encryption key for the message. An example of hybrid systems is PGP (opens new window).
The length of keys is vital. Asymmetric cryptographic keys are usually very long. One can keep in mind a general principle: the longer the key, the more difficult it is to break the code. Breaking an asymmetric key can only be done with a brute force attack, in which an attacker would need to try every possible key to find a match.
# Public and private keys
Asymmetric keys always come in pairs and offer their owner various capabilities. These capabilities are based on cryptographic mathematics. The public key is meant to be distributed to whoever is relevant, while the private key is to remain a secret. This is similar to sharing the address of your house, but keeping the key to your front door private.
# Sign and verify
Let's take a look at signing and verifying with public and private keys as an example.
Alice and Bob are communicating. Alice wants to make sure that Bob's public announcement is indeed from Bob, so:
- Bob gives Alice his public key.
- Bob signs his announcement with his private key.
- Bob sends Alice his announcement and its signature.
- Alice verifies the signature with Bob's public key.
Alice can verify the source of the announcement by checking if the signature was done with the private key that corresponds to Bob’s public key (which is already known to represent Bob).
Private keys are used to prove that messages originate from the owners of accounts known by their public keys: the signatures prove that messages were signed by someone that knows the private key that corresponds to a given public key. This is the basis of user authentication in a blockchain, and why private keys are strictly guarded secrets.
# Hierarchical-deterministic wallets
Blockchains generally maintain ledgers of user accounts and rely on public key cryptography for user authentication. Knowledge of one's public and private keys is a requirement to execute transactions. Client software applications known as wallets provide methods to generate new key pairs and store them, as well as basic services such as creating transactions, signing messages, interacting with applications, and communicating with the blockchain.
Although it is technically feasible to generate and store multiple key pairs in a wallet, key management quickly becomes tedious and error-prone for users. Given that all keys would exist only in one place, users would need to devise ways to recover their keys in adverse situations such as the loss or destruction of the computer. The more accounts, the more keys to back up.
# Do I need many addresses?
Using multiple addresses can help you improve privacy. You may be a single individual or entity, but you may want to transact with others under different aliases. Additionally, you will likely interact with more than one blockchain in the Cosmos ecosystem. Conveniently, your inevitably-different addresses on different blockchains can all stem from a single seed.
A hierarchical-deterministic wallet uses a single seed phrase to generate many key pairs to reduce this complexity. Only the seed phrase needs to be backed up.
# Cryptographic standards
The Cosmos SDK uses BIP32 (opens new window), which allows users to generate a set of accounts from an initial secret and a derivation path containing some input data, such as a blockchain identifier and account index. Since BIP39, this initial secret is mostly generated with 12 or 24 words, known as the mnemonic, taken from a standardized dictionary. Key pairs can always be mathematically reproduced from the mnemonic and the derivation path, which explains the deterministic nature of wallets.
To see BIP32 in action, visit https://www.bip32.net/ (opens new window).
Show entropy details and enter random data in the
Entropy field. This reveals an important aspect of the initial seed generation process: a source of randomness is essential. The
BIP39 Mnemonic field begins to populate with words as you provide entropy. Scroll down further and select the
Derivation Path tab. Under
Derived Addresses you will see the
Public Key and
Private Key pairs.
Like most blockchain implementations, Cosmos derives addresses from the public keys.
When using BIP39 or one of its variants, a user is required only to store their BIP39 mnemonic in a safe and confidential manner. All key pairs can be reconstructed from the mnemonic because it is deterministic. There is no practical upper limit to the number of key pairs that can be generated from a single mnemonic. The input taken from the BIP44 (opens new window) derivation path is used to generate a key pair for every blockchain using one single mnemonic. Hence the name "hierarchical-deterministic" to describe this key generation approach.
# Can you be tracked across different addresses?
A hierarchical-deterministic wallet also preserves privacy because the next public key or address cannot be deduced from the previous ones. Two addresses issued from a single mnemonic or two addresses created from two different mnemonics are indistinguishable.
# Keyrings, addresses, and address types
In the Cosmos SDK, keys are stored and managed in an object called a keyring.
Authentication is implemented as signature verification:
- Users generate transactions, sign transactions, and send signed transactions to the blockchain.
- Transactions are formatted with the public key as part of the message. Signatures are verified by confirming that the signature's public key matches the public key associated with the sender. If the message is signed by anyone other than the purported sender, the signature is invalid and the transaction is rejected.
Consider the following pseudo message in case the foregoing is unclear:
Signature into the signature verification function returns a sender. The derived sender must match the
Sender in the
Payload itself. This confirms that the
Payload could only originate from someone that knows the private key corresponding to
# Signature schemes
There is more than one implementation of the public key signature process previously described. The Cosmos SDK supports the following digital key schemes for creating digital signatures:
The different digital key schemes are implemented in different SDK packages:
- secp256k1 (opens new window), as implemented in the SDK's
crypto/keys/secp256k1package: is the most common and the same one used for Bitcoin.
- secp256r1 (opens new window), as implemented in the SDK's
- tm-ed25519 (opens new window), as implemented in the SDK's
crypto/keys/ed25519package: is supported only for consensus validation.
BaseAccount (opens new window) object provides the basic account implementation that stores authentication information.
# Public keys
Public keys are generally not used to reference accounts (see the following section, Address). Public keys do exist and they are accessible through the
cryptoTypes.PubKey (opens new window) interface. This facilitates operations which developers may find useful, such as signing off-chain messages or using a public key for other out-of-band operations.
An address is public information normally used to reference an account. Addresses are derived from public keys using ADR-28 (opens new window). Three types of addresses specify a context when an account is used:
AccAddress(opens new window) identifies users, which are the sender of a message.
ValAddress(opens new window) identifies validator operators.
ConsAddress(opens new window) identifies validator nodes that are participating in consensus. Validator nodes are derived using the ed25519 (opens new window) curve.
The keyring object stores and manages multiple accounts. The keyring object implements the
Keyring (opens new window) interface in the Cosmos SDK.
# Code example
In the previous section, your ABCI application accepted anonymous checkers moves. This is a problem. You can restrict moves to the right player with accounts.
It is necessary to differentiate between players and other actors. This helps assure there is no identity spoofing, that players do not play out of turn, and rewards are paid to the correct winner. You are also going to store the creator of a game, which may or may not be a player.
First define some elements of the eventual stored game:
How would you extract and serialize addresses? Handle the extraction like this:
Handle the serialization as follows:
You will only accept the right players when it comes to transactions.
Remaining game object
Defining the players is good, but the stored game is not complete unless you add game details like the current board state and the game's unique identifier. Conveniently, you can serialize (opens new window) and deserialize (opens new window) the board state. You can already confirm the following struct:
If you want to go beyond these out-of-context code samples and instead see more details on defining this, head to Run Your Own Chain
# Next up
In the next section, you will learn how transactions are generated and handled in the Cosmos SDK.