|
1 | | -License: GPL-3.0-or-later WITH Classpath-exception-2.0 |
| 1 | +# Subkey |
| 2 | + |
| 3 | +Subkey is a commandline utility included with Substrate. It allows generating and restoring keys for Substrate based chains such as Polkadot, Kusama and a growing number of parachains and Substrate based projects. |
| 4 | + |
| 5 | +`subkey` provides a few sub-commands to generate keys, check keys, sign messages, verify messages, etc... |
| 6 | + |
| 7 | +You can see the full list of commands with `subkey --help`. Most commands have additional help available with for instance `subkey generate --help` for the `generate` command. |
| 8 | + |
| 9 | +## Satefy first |
| 10 | + |
| 11 | +`subkey` does not need an internet connection to work. Indeed, for the best security, you should be using `subkey` on a machine that is **not connected** to the internet. |
| 12 | + |
| 13 | +`subkey` deals with **seeds** and **private keys**. Make sure to use `subkey` in a safe environment (ie. no one looking over your shoulder) and on a safe computer (ie. no one able to check you commands history). |
| 14 | + |
| 15 | +If you save any output of `subkey` into a file, make sure to apply proper permissions and/or delete the file as soon as possible. |
| 16 | + |
| 17 | +## Usage |
| 18 | + |
| 19 | +The following guide explains *some* of the `subkey` commands. For the full list and the most up to date documentation, make sure to check the integrated help with `subkey --help`. |
| 20 | + |
| 21 | +### Generate a random account |
| 22 | + |
| 23 | +Generating a new key is as simple as running: |
| 24 | + |
| 25 | + subkey generate |
| 26 | + |
| 27 | +The output looks similar to: |
| 28 | + |
| 29 | +``` |
| 30 | +Secret phrase `hotel forest jar hover kite book view eight stuff angle legend defense` is account: |
| 31 | + Secret seed: 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d |
| 32 | + Public key (hex): 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 |
| 33 | + Account ID: 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 |
| 34 | + SS58 Address: 5Hpm9fq3W3dQgwWpAwDS2ZHKAdnk86QRCu7iX4GnmDxycrte |
| 35 | +``` |
| 36 | + |
| 37 | +--- |
| 38 | +☠️ DO NT RE-USE ANY OF THE SEEDS AND SECRETS FROM THIS PAGE ☠️. |
| 39 | + |
| 40 | +You can read more about security and risks in [SECURITY.md](./SECURITY.md) and in the [Polkadot Wiki](https://wiki.polkadot.network/docs/learn-account-generation). |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +The output above shows a **secret phrase** (also called **mnemonic phrase**) and the **secret seed** (also called **Private Key**). Those 2 secrets are the pieces of information you MUST keep safe and secret. All the other information below can be derived from those secrets. |
| 45 | + |
| 46 | +The output above also show the **public key** and the **Account ID**. Those are the independant from the network where you will use the key. |
| 47 | + |
| 48 | +The **SS58 address** (or **Public Address**) of a new account is a reprensentation of the public keys of an account for a given network (for instance Kusama or Polkadot). |
| 49 | + |
| 50 | +You can read more about the SS58 format in the [substrate wiki](https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)) and see the list of reserved prefixes in the [Polkadot wiki](https://wiki.polkadot.network/docs/build-ss58-registry). |
| 51 | + |
| 52 | +For instance, considering the previous seed `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` the SS58 addresses are: |
| 53 | +- Polkadot: `16m4J167Mptt8UXL8aGSAi7U2FnPpPxZHPrCgMG9KJzVoFqM` |
| 54 | +- Kusama: `JLNozAv8QeLSbLFwe2UvWeKKE4yvmDbfGxTuiYkF2BUMx4M` |
| 55 | + |
| 56 | +### Json output |
| 57 | + |
| 58 | +`subkey` can calso generate the output as *json*. This is useful for automation. |
| 59 | + |
| 60 | +command: |
| 61 | +``` |
| 62 | +subkey generate --output-type json |
| 63 | +``` |
| 64 | + |
| 65 | +output: |
| 66 | +``` |
| 67 | +{ |
| 68 | + "accountId": "0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515", |
| 69 | + "publicKey": "0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515", |
| 70 | + "secretPhrase": "hotel forest jar hover kite book view eight stuff angle legend defense", |
| 71 | + "secretSeed": "0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d", |
| 72 | + "ss58Address": "5Hpm9fq3W3dQgwWpAwDS2ZHKAdnk86QRCu7iX4GnmDxycrte" |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +So if you only want to get the `secretSeed` for instance, you can use: |
| 77 | + |
| 78 | +command: |
| 79 | +``` |
| 80 | +subkey generate --output-type json | jq -r .secretSeed |
| 81 | +``` |
| 82 | + |
| 83 | +output: |
| 84 | +``` |
| 85 | +0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d |
| 86 | +``` |
| 87 | + |
| 88 | +### Additional user-defined password |
| 89 | + |
| 90 | +`subkey` supports an additional user-defined secret that will be appended to the seed. Let's see the following example: |
| 91 | + |
| 92 | + subkey generate --password extra_secret |
| 93 | + |
| 94 | +output: |
| 95 | +``` |
| 96 | +Secret phrase `soup lyrics media market way crouch elevator put moon useful question wide` is account: |
| 97 | + Secret seed: 0xe7cfd179d6537a676cb94bac3b5c5c9cb1550e846ac4541040d077dfbac2e7fd |
| 98 | + Public key (hex): 0xf6a233c3e1de1a2ae0486100b460b3ce3d7231ddfe9dadabbd35ab968c70905d |
| 99 | + Account ID: 0xf6a233c3e1de1a2ae0486100b460b3ce3d7231ddfe9dadabbd35ab968c70905d |
| 100 | + SS58 Address: 5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC |
| 101 | +``` |
| 102 | + |
| 103 | +Using the `inspect` command (see more details below), we see that knowning only the **secret seed** is no longer sufficient to recover the account: |
| 104 | + |
| 105 | + subkey inspect "soup lyrics media market way crouch elevator put moon useful question wide" |
| 106 | + |
| 107 | +which recovers the account `5Fe4sqj2K4fRuzEGvToi4KATqZfiDU7TqynjXG6PZE2dxwyh` and not `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC` as we expected. The additional user-defined **password** (`extra_secret` in our example) is now required to fully recover the account. Let's inspect the the previous mnemonic, this time passing also the required `password` as shown below: |
| 108 | + |
| 109 | + subkey inspect --password extra_secret "soup lyrics media market way crouch elevator put moon useful question wide" |
| 110 | + |
| 111 | +This time, we properly recovered `5He5pZpc7AJ8evPuab37vJF6KkFDqq9uDq2WXh877Qw6iaVC`. |
| 112 | + |
| 113 | +### Inspecting a key |
| 114 | + |
| 115 | +If you have *some data* about a key, `subkey inpsect` will help you discover more information about it. |
| 116 | + |
| 117 | +If you have **secrets** that you would like to verify for instance, you can use: |
| 118 | + |
| 119 | + subkey inspect < mnemonic | seed > |
| 120 | + |
| 121 | +If you have only **public data**, you can see a subset of the information: |
| 122 | + |
| 123 | + subkey inspect --public < pubkey | address > |
| 124 | + |
| 125 | +**NOTE**: While you will be able to recover the secret seed from the mnemonic, the opposite is not possible. |
| 126 | + |
| 127 | +**NOTE**: For obvious reasons, the **secrets** cannot be recovered from passing **public data** such as `pubkey` or `address` as input. |
| 128 | + |
| 129 | +command: |
| 130 | +``` |
| 131 | +subkey inspect 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d |
| 132 | +``` |
| 133 | + |
| 134 | +output: |
| 135 | +``` |
| 136 | +Secret Key URI `0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d` is account: |
| 137 | + Secret seed: 0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d |
| 138 | + Public key (hex): 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 |
| 139 | + Account ID: 0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 |
| 140 | + SS58 Address: 5Hpm9fq3W3dQgwWpAwDS2ZHKAdnk86QRCu7iX4GnmDxycrte |
| 141 | +``` |
| 142 | + |
| 143 | +### Signing |
| 144 | + |
| 145 | +`subkey` allows using a **secret key** to sign a random message. The signature can then be verified by anyone using your **public key**: |
| 146 | + |
| 147 | + echo -n <msg> | subkey sign --suri <seed|mnemonic> |
| 148 | + |
| 149 | +example: |
| 150 | + |
| 151 | + MESSAGE=hello |
| 152 | + SURI=0xa05c75731970cc7868a2fb7cb577353cd5b31f62dccced92c441acd8fee0c92d |
| 153 | + echo -n $MESSAGE | subkey sign --suri $SURI |
| 154 | + |
| 155 | +output: |
| 156 | + |
| 157 | + 9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c |
| 158 | + |
| 159 | +**NOTE**: Each run of the `sign` command will yield a different output. While each signature is different, they are all valid. |
| 160 | + |
| 161 | +### Verifying a signature |
| 162 | + |
| 163 | +Given a message, a signature and an address, `subkey` can verify whether the **message** has been digitally signed by the holder (or one of the holders) of the **private key** for the given **address**: |
| 164 | + |
| 165 | + echo -n <msg> | subkey verify <sig> <address> |
| 166 | + |
| 167 | +example: |
| 168 | + |
| 169 | + MESSAGE=hello |
| 170 | + URI=0xfec70cfbf1977c6965b5af10a4534a6a35d548eb14580594d0bc543286892515 |
| 171 | + SIGNATURE=9201af3788ad4f986b800853c79da47155f2e08fde2070d866be4c27ab060466fea0623dc2b51f4392f4c61f25381a62848dd66c5d8217fae3858e469ebd668c |
| 172 | + echo -n $MESSAGE | subkey verify $SIGNATURE $URI |
| 173 | + |
| 174 | +output: |
| 175 | + |
| 176 | + Signature verifies correctly. |
| 177 | + |
| 178 | +A failure looks like: |
| 179 | + |
| 180 | + Error: SignatureInvalid |
| 181 | + |
| 182 | +### Using the vanity generator |
| 183 | + |
| 184 | +You can use the included vanity generator to find a seed that provides an address which includes the desired pattern. Be warned, depending on your hardware this may take a while. |
| 185 | + |
| 186 | +command: |
| 187 | +``` |
| 188 | +subkey vanity --network polkadot --pattern bob |
| 189 | +``` |
| 190 | + |
| 191 | +output: |
| 192 | +``` |
| 193 | +Generating key containing pattern 'bob' |
| 194 | +best: 190 == top: 189 |
| 195 | +Secret Key URI `0x8c9a73097f235b84021a446bc2826a00c690ea0be3e0d81a84931cb4146d6691` is account: |
| 196 | + Secret seed: 0x8c9a73097f235b84021a446bc2826a00c690ea0be3e0d81a84931cb4146d6691 |
| 197 | + Public key (hex): 0x1a8b32e95c1f571118ea0b84801264c3c70f823e320d099e5de31b9b1f18f843 |
| 198 | + Account ID: 0x1a8b32e95c1f571118ea0b84801264c3c70f823e320d099e5de31b9b1f18f843 |
| 199 | + SS58 Address: 1bobYxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE |
| 200 | +``` |
| 201 | + |
| 202 | +`Bob` now got a nice address starting with his name: 1**bob**YxBPjZWRPbVo35aSwci1u5Zmq8P6J2jpa4kkudBZMqE. |
| 203 | + |
| 204 | +**Note**: While `Bob`, having a short name (3 chars), got a result rather quickly, it will take much longer for `Alice` who has a much longer name, thus the chances to generate a random address that contains the chain `alice` will be much smaller. |
| 205 | + |
| 206 | +## License |
| 207 | + |
| 208 | +License: GPL-3.0-or-later WITH Classpath-exception-2.0 |
0 commit comments