We all know we need to keep our secret key / mnemonic safe. We know they are used to sign our transactions. Now it's time to know what actually happens under the hood when we are generating our wallets and using our secrets.
Let's start with some terminology. When I'm talking about an account, I refer to what most people call a wallet. An account is active on the XRP ledger when activated by depositing the account reserve (currently 20 XRP) or more to an account address.
When I'm talking about a wallet, I refer to software that may or may not run on a piece of specialized hardware. This can be Toast Wallet, a Ledger Nano or even a piece of code you wrote to sign transactions and send them to the XRP ledger.
I'll refer to your rXXXXXXXXXX...
code as your account address. While most people call their sXXXXXXXXXX...
code their secret, this string is actually called your family seed. I will explain the difference in the second half of this blog.
Transactions
A transaction to be submitted to the XRP ledger is a JSON object. JSON is an open-standard file format that uses human-readable text to transmit data objects.
A transaction can be a Payment, to send XRP from one account to another. There are other transaction types on the XRP ledger as well, like transactions to modify account settings, offers (decentralized exchange), escrows, etc.
The JSON object for a simple Payment transaction in JSON format looks like this:
The transaction contains:
- The transaction type (Payment)
- The account (sending the transaction)
- The destination account
- The amount of XRP (in drops, so 1,000,000 = 1 XRP)
- The fee (in drops)
- The sending account Sequence (+1 on every succesful transaction sent by the sending account)
This transaction can be sent to a rippled node. This rippled node will then distribute the transaction to the network. Validators will vote and if the transaction is OK, it will be added to the next block on the blockchain. Your XRP moved from your account to the happy recipient.
Signed transaction
How did all the rippled servers and validators know the transaction was really yours to make? Couldn't you have put any account address in the transaction?
Nope.
Because you need to sign the transaction, and submit the signed transaction to a rippled node.
Signing your transaction means you'll have to prove you are allowed to spend funds for the account sending the transaction. That's what your secret or mnemonic is for. I will discuss this later.
Signing is like putting your signature under a letter and putting a stamp on a document, proving the document is official and actually came from you. With one big difference. Your signature contains a blueprint of the document you are putting it under. Your signature is reflecting the document contents, while still being demonstrably and verifiable yours.
The mind-boggling thing about the cryptography used is that the entire process is one way: everyone can verify the signature is yours and the signature is matching the document contents, without exposing the way signature should be for other document contents!
Key pair
To create generate your signature for a specific transaction, your hexadecimal private key will be used.
The generated signature and the matching hexadecimal public key will be added to your transaction contents.
Your hexadecimal public key and private key are together called your key pair
Your key pair really is a pair: they cryptographically belong together. The public key can be derived from the private key and it can be cryptographically verified if a signature is signed using the private key matching a given public key.
Sample keypair
Private key:
000762EED5BA4F378FFA60621C6DEF72F4A0A579112ADA5F5D6B2A35EC27E893A5
Public key, derived from the private key:
0203A564B266EE3F01AADD3A87289DDE215AAC70EF62F9019EE5B14967A370E1A9
You probably don't know your own key pair. At least: not directly. Indirectly you do: your hexadecimal private key is derived from the secret you do know, and your account address (the rXXXXXXXXX...
string) is derived from your hexadecimal public key.
Schematic view of what happens when you sign a transaction (local) and send the transaction to a rippled node:
As you can see, you start with the transaction. Your client (wallet software) then:
- Hashes your transaction. Hashing maps input data to a fixed size string (hash). The same input data will always result in the same hash, but if only one character changes, the hash will completely change as well. Hashing is one way: you can't convert an hash back into the input data.
- Signs the hashed transaction with your private key.
- Your unique transaction signature and your public key are then added to your transaction, and sent to the network.
Now everyone can check if your transaction is valid. Your signature can be verified by checking if the signature actually matches the transaction and the public key.
How account addresses, mnemonic, secret and key pairs are born
There are two types of secret information people use to "own their account". Most wallet software uses the sXXXXXXXXXX...
one, called the family seed. A few (like the Ledger Nano) use a list of words, called a mnemonic. (There is a third, less secure method: a plain passphrase).
The three methods to generate and store account secrets, keys and derive your account address are displayed this image:
The most important thing to realize when you look at the image displayed above is the fact that everything is one way. The key pair can be derived from a family seed or mnemonic, but you can't go back. Your public key can be derived from your private key, but not the other way around.
The only way back is to verify if a public key and signature are actually a valid result of the private key.
There are several links in the image, these links will take you to code examples (nodejs). Since it's an image they don't work, here's a list:
- Generate a family seed, derive the keypair and derive the account address:
https://runkit.com/wietsewind/generate-ripple-wallet - Generate (or manually enter) a mnemonic, create a seed buffer, derive a keypair and derive the account address:
https://runkit.com/wietsewind/mnemonic-with-ripple-keypairs-w-o-ripplelib - Derive the hexadecimal public key from a hexadecimal private key and derive the account address:
https://runkit.com/wietsewind/hex-private-key-to-address-with-ripple-lib - And... The "plain passphrase" method:
https://runkit.com/wietsewind/ripple-wallet-generator-raw