diff --git a/_includes/guide_wallets.md b/_includes/guide_wallets.md index b9cf1848..e6eb779f 100644 --- a/_includes/guide_wallets.md +++ b/_includes/guide_wallets.md @@ -158,7 +158,7 @@ As illustrated above, HD key derivation takes four inputs: * The [index][key index]{:#term-key-index}{:.term} number is a 32-bit integer specified by the program. In the normal form shown in the above illustration, the parent chain -code and the index number are fed into a one-way cryptographic hash +code, the parent public key, and the index number are fed into a one-way cryptographic hash ([HMAC-SHA512][]) to produce 512 bits of deterministically-generated-but-seemingly-random data. The seemingly-random 256 bits on the righthand side of the hash output are @@ -218,14 +218,14 @@ which makes them special. Deriving [child extended keys][child extended key]{:#term-child-extended-key}{:.term} from parent extended keys is more nuanced than described earlier due to the presence of two extended private key derivation formulas. The normal formula, described above, combines -together only the index number and the parent chain code to create the +together the index number, the parent chain code, and the parent public key to create the child chain code and the integer value which is combined with the parent private key to create the child private key. ![Creating Child Public Keys From An Extended Private Key](/img/dev/en-hd-private-parent-to-private-child.svg) The hardened formula, illustrated above, combines together the index -number, the parent chain code, and also the parent private key to create +number, the parent chain code, and the parent private key to create the data used to generate the child chain code and child private key. This formula makes it impossible to create child public keys without knowing the parent private key. In other words, parent extended public @@ -235,13 +235,22 @@ Because of that, a [hardened extended private key][]{:#term-hardened-extended-private-key}{:.term} is much less useful than a normal extended private key---however, it's more secure against multi-level key compromise. If an attacker gets a normal parent -chain code, he can brute-force find all 231 normal chain +chain code and parent public key, he can brute-force find all 231 normal chain codes deriving from it. If the attacker also obtains a child, grandchild, or further-descended private key, he can use the chain code to generate all -of the extended private keys descending from that private key. +of the extended private keys descending from that private key, as +shown in the grandchild and great-grandchild generations of the illustration below. ![Cross-Generational Key Compromise](/img/dev/en-hd-cross-generational-key-compromise.svg) +Perhaps worse, the attacker can reverse the normal child private key +derivation formula and subtract a parent chain code from a child private +key to recover the parent private key, as shown in the child and +parent generations of the illustration above. This means an attacker +who acquires an extended public key and any private key descended from +it can recover that public key's private key and all keys descended from +it. + For this reason, the chain code part of an extended public key should be better secured than standard public keys and users should be advised against exporting even non-extended private keys to diff --git a/en/developer-reference.md b/en/developer-reference.md index 83e250fa..c93aa32c 100644 --- a/en/developer-reference.md +++ b/en/developer-reference.md @@ -22,7 +22,6 @@ title: "Developer Reference - Bitcoin" {% include ref_block_chain.md %} {% include ref_transactions.md %} {% include ref_wallets.md %} -{% include ref_payment_processing.md %} ## Bitcoin Core APIs diff --git a/img/dev/en-hd-cross-generational-key-compromise.dot b/img/dev/en-hd-cross-generational-key-compromise.dot index a41b9105..dead1601 100644 --- a/img/dev/en-hd-cross-generational-key-compromise.dot +++ b/img/dev/en-hd-cross-generational-key-compromise.dot @@ -3,47 +3,73 @@ digraph extended { size=6.25; rankdir=LR; penwidth=1.75; -node [ penwidth = 1.75, shape = "box" ]; -edge [ penwidth = 1.75 ]; +node [ fontname="Sans", penwidth = 1.75, shape = "box" ]; +edge [ fontname="Sans", penwidth = 1.75, style = "" ]; +graph [ fontname="Sans" ]; nodesep=0.15; -splines = ortho; +splines = false; ranksep = 0.7; subgraph cluster_parent { - attacker_parent_private_key [ label = "Private", style = "invis" ]; - attacker_parent_chain_code [ label = "Chain", style = "filled" ]; - attacker_parent_public_key [ label = "Public", style = "invis" ]; + parent_private_key [ label = "Private", style = "" ]; + parent_chain_code [ label = "Chain", style = "filled" ]; + parent_public_key [ label = "Public", style = "filled" ]; - label = "Parent" + label = "Parent\n " } subgraph cluster_child { - attacker_child_private_key [ label = "Private", style = "filled" ]; - attacker_child_chain_code [ label = "Chain" ]; - attacker_child_public_key [ label = "Public" ]; + child_private_key [ label = "Private" ]; + child_chain_code [ label = "Chain" ]; + child_public_key [ label = "Public" ]; - label = "Child" + label = "Child\n " } subgraph cluster_grandchild { - attacker_grandchild_private_key [ label = "Private" ]; - attacker_grandchild_chain_code [ label = "Chain" ]; - attacker_grandchild_public_key [ label = "Public" ]; + grandchild_private_key [ label = "Private", style = "filled" ]; + grandchild_chain_code [ label = "Chain" ]; + grandchild_public_key [ label = "Public" ]; - label = "Grandchild" + label = "Grandchild\n " +} + +subgraph cluster_greatgrandchild { + greatgrandchild_private_key [ label = "Private" ]; + greatgrandchild_chain_code [ label = "Chain" ]; + greatgrandchild_public_key [ label = "Public" ]; + + label = "Great-\nGrandchild" } +parent_public_key -> child_public_key; +parent_public_key -> child_chain_code; +parent_chain_code -> child_chain_code [ label = "Normal Child\nKey Derivation", weight = 100 ]; +parent_chain_code -> child_public_key; +parent_chain_code -> child_private_key [ style = "invis" ]; +parent_private_key -> child_private_key [ dir = "back", style = "", label = "Parent Key\nDerivation" ]; -attacker_parent_public_key -> attacker_child_public_key [ style = "invis" ]; -attacker_parent_chain_code -> attacker_child_chain_code; -attacker_parent_chain_code -> attacker_child_public_key [ style = "invis" ]; -attacker_parent_private_key -> attacker_child_private_key [style = "invis" ]; +parent_chain_code -> parent_private_key [ constraint = false ]; + +child_private_key -> grandchild_private_key [ dir = "back", style = "" ]; +child_public_key -> grandchild_chain_code; +child_public_key -> grandchild_public_key; +child_chain_code -> grandchild_private_key [ style = "invis" ]; +child_chain_code -> grandchild_public_key; +child_chain_code -> grandchild_chain_code [ weight = 100 ]; + +child_chain_code -> child_private_key [ constraint = false ] + +grandchild_private_key -> greatgrandchild_private_key; +grandchild_public_key -> greatgrandchild_chain_code; +grandchild_public_key -> greatgrandchild_public_key; +grandchild_chain_code -> greatgrandchild_private_key; +grandchild_chain_code -> greatgrandchild_public_key; +grandchild_chain_code -> greatgrandchild_chain_code [ weight = 100 ]; + +grandchild_chain_code -> grandchild_private_key [ constraint = false, style = "invis" ] +greatgrandchild_chain_code -> greatgrandchild_private_key [ constraint = false, style = "invis" ] -attacker_child_private_key -> attacker_grandchild_private_key; -attacker_child_public_key -> attacker_grandchild_public_key; -attacker_child_chain_code -> attacker_grandchild_private_key; -attacker_child_chain_code -> attacker_grandchild_public_key; -attacker_child_chain_code -> attacker_grandchild_chain_code; label = "Cross-Generational Key Compromise" } diff --git a/img/dev/en-hd-cross-generational-key-compromise.png b/img/dev/en-hd-cross-generational-key-compromise.png index b44c0819..8869dcf0 100644 Binary files a/img/dev/en-hd-cross-generational-key-compromise.png and b/img/dev/en-hd-cross-generational-key-compromise.png differ diff --git a/img/dev/en-hd-cross-generational-key-compromise.svg b/img/dev/en-hd-cross-generational-key-compromise.svg index bd0c21ca..c0bb8e18 100644 --- a/img/dev/en-hd-cross-generational-key-compromise.svg +++ b/img/dev/en-hd-cross-generational-key-compromise.svg @@ -4,93 +4,189 @@ - - + + extended - -Cross-Generational Key Compromise + +Cross-Generational Key Compromise cluster_parent - -Parent + +Parent + cluster_child - -Child + +Child + cluster_grandchild - -Grandchild + +Grandchild + - - -attacker_child_private_key - -Private +cluster_greatgrandchild + +Great- +Grandchild - - -attacker_parent_chain_code + +parent_private_key + +Private + + +child_private_key + +Private + + +parent_private_key->child_private_key + + +Parent Key +Derivation + + +parent_chain_code Chain - -attacker_child_chain_code - -Chain + +parent_chain_code->parent_private_key + + - -attacker_parent_chain_code->attacker_child_chain_code - - + + +child_chain_code + +Chain - -attacker_child_public_key - -Public + +parent_chain_code->child_chain_code + + +Normal Child +Key Derivation - - - - -attacker_grandchild_private_key - -Private + +child_public_key + +Public - -attacker_child_private_key->attacker_grandchild_private_key - - + +parent_chain_code->child_public_key + + - -attacker_child_chain_code->attacker_grandchild_private_key - - + +parent_public_key + +Public - -attacker_grandchild_chain_code - -Chain + +parent_public_key->child_chain_code + + - -attacker_child_chain_code->attacker_grandchild_chain_code - - + +parent_public_key->child_public_key + + - -attacker_grandchild_public_key - -Public + +grandchild_private_key + +Private - -attacker_child_chain_code->attacker_grandchild_public_key - - + +child_private_key->grandchild_private_key + + - -attacker_child_public_key->attacker_grandchild_public_key - - + +child_chain_code->child_private_key + + + + +grandchild_chain_code + +Chain + + +child_chain_code->grandchild_chain_code + + + + +grandchild_public_key + +Public + + +child_chain_code->grandchild_public_key + + + + +child_public_key->grandchild_chain_code + + + + +child_public_key->grandchild_public_key + + + + +greatgrandchild_private_key + +Private + + +grandchild_private_key->greatgrandchild_private_key + + + + + +grandchild_chain_code->greatgrandchild_private_key + + + + +greatgrandchild_chain_code + +Chain + + +grandchild_chain_code->greatgrandchild_chain_code + + + + +greatgrandchild_public_key + +Public + + +grandchild_chain_code->greatgrandchild_public_key + + + + +grandchild_public_key->greatgrandchild_chain_code + + + + +grandchild_public_key->greatgrandchild_public_key + + + + diff --git a/img/dev/en-hd-overview.dot b/img/dev/en-hd-overview.dot index 6cfcfb32..50d053e6 100644 --- a/img/dev/en-hd-overview.dot +++ b/img/dev/en-hd-overview.dot @@ -3,10 +3,11 @@ digraph extended { size=6.25; rankdir=LR; penwidth=1.75; -node [ penwidth = 1.75, shape = "box" ]; -edge [ penwidth = 1.75 ]; +node [ fontname="Sans", penwidth = 1.75, shape = "box" ]; +edge [ fontname="Sans", penwidth = 1.75 ]; +graph [ fontname="Sans" ] nodesep=0.15; -splines = ortho; +//splines = ortho; ranksep = 0.3; subgraph cluster_parent { @@ -15,24 +16,25 @@ parent_private_key [ label = "Parent Private Key" ]; parent_chain_code [ label = "Parent Chain Code" ]; parent_public_key [ label = "Parent Public Key" ]; } + child_private_key [ label = "Child Private Key" ]; child_chain_code [ label = "Child Chain Code" ]; child_public_key [ label = "Child Public Key" ]; + i_norm [ label = "Index Number" ]; hmac [ label = "One-Way Hash", style = "diagonals" ]; rel1 [ label = "Mathematical\nRelationship", shape = "none" ] rel2 [ label = "Derived\nMathematical\nRelationship", shape = "none" ] -rel1 -> parent_private_key [ weight = 0, dir = "back" ]; -rel1 -> parent_chain_code [ style = "invis" ]; -rel1 -> parent_public_key [ weight = 0 ]; +rel1 -> parent_private_key [ weight = "", dir = "back" ]; +rel1 -> parent_chain_code [ weight = "", style = "invis" ]; +rel1 -> parent_public_key [ weight = "" ]; -child_private_key -> rel2 [ weight = 0 ]; -child_chain_code -> rel2 [ weight = 1, style = "invis" ]; -child_public_key -> rel2 [ weight = 0, dir = "back" ]; +child_private_key -> rel2 [ ]; +child_chain_code -> rel2 [ style = "invis" ]; +child_public_key -> rel2 [ dir = "back" ]; -//rel1 -> rel2 [ weight = 0 ]; //parent_private_key -> parent_public_key [constraint = false, label = "Math Rel" ]; //child_private_key -> child_public_key [constraint = false, minlen = 2]; @@ -40,7 +42,9 @@ child_public_key -> rel2 [ weight = 0, dir = "back" ]; parent_private_key -> child_private_key; parent_public_key -> child_public_key; +parent_public_key -> hmac; parent_chain_code -> hmac; +parent_private_key -> hmac [ style = "invis" ]; i_norm -> hmac; hmac -> child_public_key; diff --git a/img/dev/en-hd-overview.png b/img/dev/en-hd-overview.png index edfdf9d5..48e637bc 100644 Binary files a/img/dev/en-hd-overview.png and b/img/dev/en-hd-overview.png differ diff --git a/img/dev/en-hd-overview.svg b/img/dev/en-hd-overview.svg index d4e75cf7..f9d8cb5c 100644 --- a/img/dev/en-hd-overview.svg +++ b/img/dev/en-hd-overview.svg @@ -28,11 +28,6 @@ - -parent_chain_code - -Parent Chain Code - hmac @@ -42,8 +37,14 @@ One-Way Hash + + +parent_chain_code + +Parent Chain Code + -parent_chain_code->hmac +parent_chain_code->hmac @@ -62,6 +63,11 @@ + +parent_public_key->hmac + + + rel2 Derived @@ -90,22 +96,22 @@ Index Number -i_norm->hmac - - +i_norm->hmac + + -hmac->child_private_key +hmac->child_private_key -hmac->child_chain_code +hmac->child_chain_code -hmac->child_public_key +hmac->child_public_key @@ -116,14 +122,14 @@ rel1->parent_private_key - - + + rel1->parent_public_key - - + + diff --git a/img/dev/en-hd-private-parent-to-private-child.dot b/img/dev/en-hd-private-parent-to-private-child.dot index 2bc81dfa..ddbd46d8 100644 --- a/img/dev/en-hd-private-parent-to-private-child.dot +++ b/img/dev/en-hd-private-parent-to-private-child.dot @@ -3,12 +3,14 @@ digraph extended { size=6.25; rankdir=LR; penwidth=1.75; -node [ penwidth = 1.75, shape = "box" ]; -edge [ penwidth = 1.75 ]; +node [ fontname="Sans", penwidth = 1.75, shape = "box" ]; +edge [ fontname="Sans", penwidth = 1.75 ]; +graph [ fontname="Sans" ]; nodesep=0.05; -splines = ortho; +//splines = ortho; ranksep = 1.0; subgraph cluster_hard { + style = "invis"; subgraph cluster_h_parent_extended_key { h_parent_private_key [ label = "Parent Private Key" ]; @@ -31,18 +33,16 @@ subgraph cluster_hard { hmac_hard -> child_private_key_hard; hmac_hard -> child_chain_code_hard; h_parent_private_key -> child_private_key_hard; - - label = "Hardened Private" } subgraph cluster_norm { - //style = "invis" - //label = "Creation Of Normal Child Extended Keys (Key + Chain Code)\nFrom Parent Extended Keys" + style = "invis" subgraph cluster_n_parent_extended_key { n_parent_private_key [ label = "Parent Private Key" ]; n_parent_chain_code [ label = "Parent Chain Code" ]; + n_parent_public_key [ label = "Parent Public Key" ]; } subgraph cluster_child_extended_key_norm { @@ -53,15 +53,13 @@ subgraph cluster_norm { i_norm [ label = "Index <0x80000000" ]; n_parent_chain_code -> hmac_norm; + n_parent_public_key -> hmac_norm; i_norm -> hmac_norm; hmac_norm -> child_private_key_norm; hmac_norm -> child_chain_code_norm; - n_parent_private_key -> child_private_key_norm; - - label = "Normal Private" + n_parent_private_key -> child_private_key_norm [weight = 5]; } - -label = "Creation Of Child Extended Private Keys (Key, Chain Code)" +label = "Normal (Top) And Hardened (Bottom) Child Private Key Derivation"; } diff --git a/img/dev/en-hd-private-parent-to-private-child.png b/img/dev/en-hd-private-parent-to-private-child.png index dc66ca13..83081604 100644 Binary files a/img/dev/en-hd-private-parent-to-private-child.png and b/img/dev/en-hd-private-parent-to-private-child.png differ diff --git a/img/dev/en-hd-private-parent-to-private-child.svg b/img/dev/en-hd-private-parent-to-private-child.svg index 7c2fa2cc..02e85cc3 100644 --- a/img/dev/en-hd-private-parent-to-private-child.svg +++ b/img/dev/en-hd-private-parent-to-private-child.svg @@ -4,31 +4,23 @@ - - + + extended - -Creation Of Child Extended Private Keys (Key, Chain Code) + +Normal (Top) And Hardened (Bottom) Child Private Key Derivation cluster_hard - -Hardened Private cluster_h_parent_extended_key - cluster_child_extended_key_else - cluster_norm - -Normal Private cluster_n_parent_extended_key - cluster_child_extended_key_norm - h_parent_private_key @@ -97,63 +89,73 @@ n_parent_private_key - -Parent Private Key + +Parent Private Key -child_private_key_norm - -Child Private Key +child_private_key_norm + +Child Private Key -n_parent_private_key->child_private_key_norm - - +n_parent_private_key->child_private_key_norm + + n_parent_chain_code - -Parent Chain Code + +Parent Chain Code -hmac_norm - - - - - -One-Way -Hash +hmac_norm + + + + + +One-Way +Hash n_parent_chain_code->hmac_norm - - + + + + +n_parent_public_key + +Parent Public Key + + +n_parent_public_key->hmac_norm + + -child_chain_code_norm - -Child Chain Code +child_chain_code_norm + +Child Chain Code -hmac_norm->child_private_key_norm - - +hmac_norm->child_private_key_norm + + -hmac_norm->child_chain_code_norm - - +hmac_norm->child_chain_code_norm + + -i_norm - -Index <0x80000000 +i_norm + +Index <0x80000000 -i_norm->hmac_norm - - +i_norm->hmac_norm + +