-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.html
355 lines (331 loc) · 15.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Cardo" rel="stylesheet">
<title>BIP32 Cheat Sheet</title>
<style>
body {
font-family: 'Cardo', serif;
background: #fffcf9;
}
.list-group-item {
font-size: 90%;
}
.code {
font-size: 70%;
}
.separator {
background-color: #d1ccdc;
border: 0;
height: 0.2em;
}
a, a:hover {
color: #f19953;
}
.box {
background: #fff;
border: 1px solid #d1ccdc;
padding: 2em;
}
.large_margin_top {
margin-top: 3em;
}
img {
border: 1px solid #d1ccdc;
}
</style>
</head>
<body>
<div class="container mt-5">
<div class="row">
<div class="col-12">
<h1><strong>BIP32 Cheat Sheet</strong></h1>
<p class="lead mb-5">
Implementation steps with sample code in Elixir for <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki">BIP32</a> HD Wallet standard.
</p>
<hr class="separator">
</div>
</div>
<div class="row mt-4 mb-5">
<div class="col-md-8 col-sm-12">
<h2>Mnemonic Phrase</h2>
<p class="lead mb-5">This section describes how to go from random entropy to 24 mnemonic words.</p>
<ol>
<li>
<strong>Random Entropy</strong>
<p>This is a 256bit number</p>
</li>
<li>
<strong>Build Checksum</strong>
<p>This involves running the 256bit number through SHA256, extracting the first 8 bits and appending them at the end of the 256 bit sequence</p>
</li>
<li>
<strong>Split into 11 bit sequence</strong>
<p>This next step splits the 264 bit sequence into 11 bit sequences (24 of them)</p>
</li>
<li>
<strong>Return 24 word mnemonic</strong>
<p>Map each 11 bit value to a word in the predefined dictionary</p>
</li>
</ol>
</div>
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">The dictionary is common across multiple wallets so most of the mnemonic words are inter changeable.</p>
<ol>
<li>abandon</li>
<li>ability</li>
<li>able</li>
<li>about</li>
<li>...</li>
</ol>
</div>
</div>
</div>
<hr>
<div class="row mt-4 mb-5">
<div class="col-md-6 col-sm-12 mt-5">
<img src="mnemonic_to_seed.jpg" class="img-fluid" />
</div>
<div class="col-md-6 col-sm-12 large_margin_top">
<h2>Generate the seed</h2>
<p class="lead mb-5">Stretching the 256bit entropy from menmonic words into 512bit seed</p>
<ol>
<li>
<strong>Salt</strong>
<p>Create a salt. If no password is chosen, the salt will be comprised of the string "mnemonic"</p>
</li>
<li>
<strong>Key Stretching</strong>
<p>Create initial PBKDF2 round by passing the entropy as the key and the salt as the data.</p>
</li>
<li>
<strong>Repeat 2048 times</strong>
<p>Repeat this 2048 times. The entropy parameter stays the same, while the data is the xor of the current and previous result</p>
</li>
<li>
<strong>Encode in hexadecimal</strong>
<p>Generally the seed is exported as a hex string.</p>
</li>
</ol>
</div>
</div>
<hr>
<div class="row mt-4 mb-5">
<div class="col-md-8 col-sm-12 large_margin_top">
<h2>Anatomy of an exteded key</h2>
<p class="lead mb-5">An extended key is a Base58Check encoded string that encodes a few pieces of information.</p>
<ol>
<li>
<strong>Version Number</strong>
<p>4 bytes that denote weather we're encoding a public or private key. The version number is what starts an extended by with xpub or xprv. The bytes in the version
number combined with the rest of the data produces the xpub/xprv in Base58 encoding.</p>
</li>
<li>
<strong>Depth</strong>
<p>1 byte that denotes the depth.</p>
</li>
<li>
<strong>Fingerprint</strong>
<p>4 bytes (the first 4 bytes of the SHA256 --> Ripemd160 hash of the parent key)</p>
</li>
<li>
<strong>Index</strong>
<p>4 bytes</p>
</li>
<li>
<strong>Chain Code</strong>
<p>32 bytes</p>
</li>
<li>
<strong>Key</strong>
<p class="mb-0">33 bytes - If private key it will be prepended with a zero byte</p>
</li>
</ol>
</div>
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">The derivation path includes information about the depth and index for a key.</p>
<p>m/44'/0'/0'</p>
<p>The <em>Depth</em> is how far from the m/ you are. m/0 would be depth 0, m/0/1 would be depth 1.</p>
<p>The <em>Index</em> is the number. m/2 would have an index of 2.<p>
<p>If the index is hardened (') the index is actually 2_147_483_647 + index. m/44' would be index 2_147_483_691.</p>
</div>
</div>
</div>
<div class="row mt-4 mb-5">
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">The derivation path is split into a list of numbers each representing one depth level.</p>
<p>At each subsequent step the previous key and chain code is used and the depth increased by 1.</p>
</div>
<div class="box mt-3">
<p class="lead">Elliptical Curve Cryptography</p>
<p>We are using a few operations on the Secp256k1 curve to help us compute keys in our derivations.</p>
<ul>
<li>Point multiplication</li>
<li>Point addition</li>
<li>Modulus the order of the curve</li>
</ul>
</div>
</div>
<div class="col-md-8 col-sm-12 large_margin_top">
<h2>Child Key Derivation (public, non-hardened)</h2>
<p class="lead mb-5">A non hardened child key derivation means that we will use the parent's public key to derive the child key. It also means that the index will be at most 2_147_483_647</p>
<ol>
<li>
<strong>Split the derivation path into list of integers.</strong>
<p>This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)</p>
</li>
<li>
<strong>Decode parent extended key</strong>
<p>This will result in a key, chain code, depth, index and version number.</p>
</li>
<li>
<strong>Calculate child fingerprint from parent key</strong>
<p>This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.</p>
</li>
<li>
<strong>Increase the depth and index</strong>
<p>Depth increases by 1 while index by the path number currently deriving.</p>
</li>
<li>
<strong>Calculate PBKDF2 HMAC512 of the parent chain code & key + index</strong>
<p>The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)</p>
</li>
<li>
<strong>Use resulting key to perform EC curve multiplication with G to compute child public key.</strong>
<p>This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.</p>
</li>
<li class="mb-3">
<strong>De-compress the parent public key into the X and Y coordinates.</strong>
</li>
<li class="mb-3">
<strong>Perform EC point addition of the P(X,Y) and the child public key.</strong>
<p>This step is required to get the X and Y coordinates of the resulting child key.</p>
</li>
<li>
<strong>Check if the resulting X, Y coordinate fall within the curve's finite field.</strong>
<p>The resulting extended by is just the compressed version (just the X coordinate) of the (X,Y) point. We append 02 if the Y coordinate is even or 03 otherwise. </p>
</li>
<li class="mb-3">
<strong>Encode resulting data with Base58Check</strong>
<p>The version number used will be the public one. </p>
</li>
</ol>
</div>
</div>
<hr>
<div class="row mt-4 mb-5">
<div class="col-md-8 col-sm-12 large_margin_top">
<h2>Child Key Derivation (private, un-hardened)</h2>
<p class="lead mb-5">The private child key derivation is similar to the public one with a few exceptions.</p>
<ol>
<li>
<strong>Split the derivation path into list of integers.</strong>
<p>This is a non-hardened path so we won't get any ' in the path (ie. m/0/0)</p>
</li>
<li>
<strong>Decode parent extended key</strong>
<p>This decoded key will have a 0 appended to it and we need to strip that.</p>
</li>
<li>
<strong>Calculate the public key using EC multiplcation.</strong>
<p>This is the first 4 bytes of the SHA256 -> RIPEMD160 hash functions.</p>
</li>
<li>
<strong>Compress the public key obtained in the previous step.</strong>
<p>Depth increases by 1 while index by the path number currently deriving.</p>
</li>
<li>
<strong>Use the compressed public key from previous step to calculate the fingerprint.</strong>
<p>The resulting 512bit number is the child key (first 256bits and the child chain code the rest 256bits)</p>
</li>
<li>
<strong>Calculate depth.</strong>
<p>This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.</p>
</li>
<li>
<strong>Use PBKDF2 HMAC512 to calculate child key and chaincode.</strong>
<p>This is the same point multiplication we use to derive a public key from a private key, except this time we use the parent public key to derive a child public key.</p>
</li>
<li class="mb-3">
<strong>Run the resulting key through mod curve order to ensure the point falls within the finite field.</strong>
</li>
<li class="mb-3">
<strong>Encode resulting data with Base58Check</strong>
<p>We're using the private version number here.</p>
</li>
</ol>
</div>
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">The resulting key will start with xprv</p>
</div>
</div>
</div>
<hr>
<div class="row mt-4 mb-5">
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">Why hardened and non-hardened paths?</p>
<p>There are use cases for each as well as pros and cons.</p>
<ul>
<li>
<strong>Non-hardened</strong>
<p>Non-hardened derivation is what allows us to generate addresses from a Master Public Key on a live server.</p>
<p>The danger with this method is that if one child private key and the Master Public Key is leaked, an attacker can calculate the parent private key (this compromises the whole HD wallet).</p>
</li>
<li>
<strong>Hardened</strong>
<p>Hardened key derivation is useful when you want to share a hierarchy of private keys and keep them isolated.</p>
<p>You cannot generate child addresses on a hardened path without the private key.</p>
</li>
</ul>
</div>
</div>
<div class="col-md-8 col-sm-12 large_margin_top">
<h2>Child Key Derivation (hardened)</h2>
<p class="lead mb-5">A hardened derivation offsets the index of each path integer by 2^31. All the previous steps apply except that for both private and public derivation the resulting public or private key is calculated using the parent private key. This means that you can't derive a downstream path for a hardened path.</p>
<ol>
<li>
<strong>Use resulting key to perform EC curve multiplication with G to compute child public or private key.</strong>
<p>We're using the parent private key to perform this step as stated above. This means that if we have an extended public key and we want to derive a path like m/0' we won't be able to because we don't have access to the private key which is required in this step.</p>
</li>
</ol>
</div>
</div>
<hr>
<div class="row mt-4 mb-5">
<div class="col-md-8 col-sm-12 large_margin_top">
<h2>Addresses</h2>
<p class="lead mb-5">Once we have a way to generate a tree of public keys, getting a blockchain address is only a matter of hashing or encoding it the right way.</p>
<ul>
<li>
<strong>Bitcoin</strong>
<p>A bitcoin pay-to-hash address is a SHA256 -> RIPEMD160 -> Base58Check of the compressed public key. </p>
</li>
<li>
<strong>Ripple</strong>
<p>A ripple address is similarly a SHA256 -> RIPEMD160 -> Base58Check but with a different alphabet than Bitcoin. That's why addresses look different.</p>
</li>
<li>
<strong>Ethereum</strong>
<p>Ethereum addresses start from the same precursor as Bitcoin and Ripple, except we use the un-compressed public key (concatenated X and Y), take the Keccak256 hash of that and keep the last 20 bytes.</p>
</li>
</ul>
</div>
<div class="col-md-4 col-sm-12 mt-5">
<div class="box">
<p class="lead">These are just a few examples of the top 3 coins but this scheme can be extended to support most blockchains out there. <a href="https://github.com/satoshilabs/slips/blob/master/slip-0044.md">This is a list of the supported coins</a> for the BIP44 standard.</p>
</div>
</div>
</div>
</div>
</body>
</html>