From 534252de49b204a4c2e992c489dddf917638bd0a Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Fri, 28 Mar 2014 12:21:11 +0100 Subject: [PATCH] HD Wallets: bugfix, ensure we don't store private keys that can be rederived. --- .../bitcoin/crypto/DeterministicKey.java | 4 ++-- .../com/google/bitcoin/crypto/HDUtils.java | 2 +- .../bitcoin/wallet/DeterministicKeyChain.java | 20 ++++++++-------- .../deterministic-wallet-serialization.txt | 23 ------------------- 4 files changed, 13 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/crypto/DeterministicKey.java b/core/src/main/java/com/google/bitcoin/crypto/DeterministicKey.java index ed8431e6..30516ad5 100644 --- a/core/src/main/java/com/google/bitcoin/crypto/DeterministicKey.java +++ b/core/src/main/java/com/google/bitcoin/crypto/DeterministicKey.java @@ -157,8 +157,8 @@ public class DeterministicKey extends ECKey { */ public DeterministicKey getPubOnly() { if (isPubKeyOnly()) return this; - final DeterministicKey parentPub = getParent() == null ? null : getParent().getPubOnly(); - return new DeterministicKey(getPath(), getChainCode(), getPubKeyPoint(), null, parentPub); + //final DeterministicKey parentPub = getParent() == null ? null : getParent().getPubOnly(); + return new DeterministicKey(getPath(), getChainCode(), getPubKeyPoint(), null, parent); } diff --git a/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java b/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java index 129f39d1..4cf991b6 100644 --- a/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java +++ b/core/src/main/java/com/google/bitcoin/crypto/HDUtils.java @@ -64,7 +64,7 @@ public final class HDUtils { return bytes; } - static ImmutableList append(ImmutableList path, ChildNumber childNumber) { + public static ImmutableList append(ImmutableList path, ChildNumber childNumber) { return ImmutableList.builder().addAll(path).add(childNumber).build(); } diff --git a/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java b/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java index a537ed6c..c222ae12 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java +++ b/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java @@ -233,22 +233,21 @@ public class DeterministicKeyChain implements EncryptableKeyChain { public DeterministicKey getKey(KeyPurpose purpose) { lock.lock(); try { - DeterministicKey key; - List lookahead; + DeterministicKey key, parentKey; + int index; if (purpose == KeyPurpose.RECEIVE_FUNDS) { - issuedExternalKeys++; - lookahead = maybeLookAhead(externalKey, issuedExternalKeys); - // TODO: Handle the case where the derived key is >= curve order. - key = HDKeyDerivation.deriveChildKey(externalKey, issuedExternalKeys - 1); + index = ++issuedExternalKeys; + parentKey = externalKey; } else if (purpose == KeyPurpose.CHANGE) { - issuedInternalKeys++; - lookahead = maybeLookAhead(internalKey, issuedInternalKeys); - // TODO: Handle the case where the derived key is >= curve order. - key = HDKeyDerivation.deriveChildKey(internalKey, issuedInternalKeys - 1); + index = ++issuedInternalKeys; + parentKey = internalKey; } else { throw new IllegalArgumentException("Unknown key purpose " + purpose); } + // TODO: Handle the case where the derived key is >= curve order. + List lookahead = maybeLookAhead(parentKey, index); basicKeyChain.importKeys(lookahead); + key = hierarchy.get(HDUtils.append(parentKey.getPath(), new ChildNumber(index - 1, false)), false, false); return key; } finally { lock.unlock(); @@ -665,6 +664,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain { for (int i = 0; i < needed; i++) { // TODO: Handle the case where the derived key is >= curve order. DeterministicKey key = HDKeyDerivation.deriveChildKey(parent, numChildren + i); + key = key.getPubOnly(); hierarchy.putKey(key); result.add(key); } diff --git a/core/src/test/resources/com/google/bitcoin/wallet/deterministic-wallet-serialization.txt b/core/src/test/resources/com/google/bitcoin/wallet/deterministic-wallet-serialization.txt index 129c28c3..bab18199 100644 --- a/core/src/test/resources/com/google/bitcoin/wallet/deterministic-wallet-serialization.txt +++ b/core/src/test/resources/com/google/bitcoin/wallet/deterministic-wallet-serialization.txt @@ -44,7 +44,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "gA\025\241\366\211\023k\267B \326\365\025\v\214X\001c\364\200\247\246#o\307J\357\353h\242N" public_key: "\003\306\337\017!F\303;\257Z\320:w\353\304\021L#\250\255\345X\023k\233\323\273\253\331s\352\362\024" creation_timestamp: 0 deterministic_key { @@ -55,7 +54,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "&\371/\\\237WO\250\260\366\252\245$\360\203\020\310o\3472T\204_\306\371\3547\352M\310:i" public_key: "\003\341#\025-h\212\273XE\211\266\224|\222\251\335\375?\275A\350rU\341\212\361\221\267\303\313I\t" creation_timestamp: 0 deterministic_key { @@ -66,7 +64,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\360\242\254\001/\301\370\314!NV(j\370C\254\225\034\022!\035h\350i\0057\376\223\027\224i\266" public_key: "\002\375\317\3177\306\272\204\344\210\367\203\326\tn\306\376\322\004\264\r36W\262/!\t>FN\215\302" creation_timestamp: 0 deterministic_key { @@ -77,7 +74,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\241\262\266\022\252\\\372\271\005\356\367\241\270\307\372]\253\370\310Dj\bT&y\311~[\023\340\0355" public_key: "\003\031\256\332?\356\255\270o\001\232\327\262\207@\275\315\355\336]\002\020\v\302)\361\037U\223\372\233\266e" creation_timestamp: 0 deterministic_key { @@ -88,7 +84,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "n\t_\254\221%L\355XYc\353\ae\355{5j\342\272\026\277\341\t~\325\374-WR." public_key: "\003\273\222i0kH\005\313e\373\306c\021\340u\275\353\231\224i\333\357\017r\372\200\036PW\311\356," creation_timestamp: 0 deterministic_key { @@ -99,7 +94,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: ">7a\'?=\203(\247c\345\242\274.w\\\006\365\337\256m\224\001a6\306\321\034\222r g" public_key: "\003\300\022\330\270/Jy2\246\226\266\310t\344\241Q\342r\275\027\a\326:\377\230\343\037t\032\351V\207" creation_timestamp: 0 deterministic_key { @@ -110,7 +104,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\205y\v\327@\220D\247\2703\n\342O`\245\252\203\304\347\3532\216u\255g\236}\224\a\345\251\205" public_key: "\002\350\257\214\317@\262\314sC\021[\000\201;(\000\253\326\275\335\233\'1\206\252\242@B/Fl\266" creation_timestamp: 0 deterministic_key { @@ -121,7 +114,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\037\252\207l\370\342\336\347)\254\340\215\337\000\272o\265\3705\261\2443>\035S\323\317\035\230Y\223\356" public_key: "\002\361z\203\341\345\350\214L\272\262\301-8/\246xX\'\r\027\026#^M\a\313\277\356\354B\022" creation_timestamp: 0 deterministic_key { @@ -132,7 +124,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "M\000\3201\320;\247RQP\305\224\322\300Z5G\242\265\366K\000l\\\304\207~\265\n\326\033\"" public_key: "\003l\021W\350G\026kc\225\213\307Rv1[p\270P\r\266T\275\021\b\270\335\'\270\254\307\242:" creation_timestamp: 0 deterministic_key { @@ -143,7 +134,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\024\370\267\224\2021T\212`\245\v&\207^V\2670[h\321\327\035\\\361lU)h%\257\222\250" public_key: "\003KaP\210J\320\354\202\024#*#\323\276i\\\004\341\225\253qw_\235\371\370\316\315N\rZ\031" creation_timestamp: 0 deterministic_key { @@ -154,7 +144,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\263\364\244\214\361\267Z\254y65\024fW&\00475\374\317jP\021\332[[\276\363\016\2636\322:\321\361\032!?q-\320" creation_timestamp: 0 deterministic_key { @@ -198,7 +184,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\301\335\371\036\b\235k\352\324\356\037\345\223x8\267\347\220o\357\265\246V\223\251\3325\212\036\a\320\367" public_key: "\003\204\311|\002}\002\201IQ\003c\253\335Ay\220@3\210\001~\345L\216u\030\217\232\262m{\371" creation_timestamp: 0 deterministic_key { @@ -209,7 +194,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\256Lyzha\250\220w\022\0231\036\316\'\313\321\324\313\306\313\032{\2773\273\227\351<\266\223\036" public_key: "\003\376WS\201\255et\362H\372\261\233\332\265\250\266Y\344\336y\240\'\025\374\222\274\261\351\032\212\313" creation_timestamp: 0 deterministic_key { @@ -220,7 +204,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\'X\227U\337=\273\336\211r{\241\\c\257\341zp\341\224\353p\322Pt\254\365\206q\235\210\005\2323F\351" public_key: "\003\226\253\321\200\001\346u\020_C9\nj\001} \212\027\341-f\f=\320~\311\200ck@\361\341" creation_timestamp: 0 deterministic_key { @@ -275,7 +254,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\031\223\347\022q\261\345\032\367+\201\022\f6\242F\032\303t\361;O\372\275rp\246X\254\022\314\272" public_key: "\0036\201\035\327\312\220\'\360\325B\276\372\347\aFp\265\252\vs\243\245\210\004y\236\250>\353[U" creation_timestamp: 0 deterministic_key { @@ -286,7 +264,6 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "2\003\fr4\335b\001#\204O\231\310\274\324\037\243\335\243A\003\017\325\344\rnXl\006R)\367" public_key: "\003J\371[{Vs\232A\260\343\376!\265\a\031`\0239\277=jd\n\230\270\034\350#\302}x\334" creation_timestamp: 0 deterministic_key {