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 bd32db8ed..0e6418d2b 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java +++ b/core/src/main/java/com/google/bitcoin/wallet/DeterministicKeyChain.java @@ -80,6 +80,7 @@ import static com.google.common.collect.Lists.newLinkedList; */ public class DeterministicKeyChain implements EncryptableKeyChain { private static final Logger log = LoggerFactory.getLogger(DeterministicKeyChain.class); + public static final String DEFAULT_PASSPHRASE_FOR_MNEMONIC = ""; private final ReentrantLock lock = Threading.lock("DeterministicKeyChain"); @@ -129,7 +130,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain { * object and the default entropy size. */ public DeterministicKeyChain(SecureRandom random) { - this(random, DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS, "", Utils.currentTimeSeconds()); + this(random, DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS, DEFAULT_PASSPHRASE_FOR_MNEMONIC, Utils.currentTimeSeconds()); } /** @@ -137,7 +138,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain { * object and of the requested size in bits. */ public DeterministicKeyChain(SecureRandom random, int bits) { - this(random, bits, "", Utils.currentTimeSeconds()); + this(random, bits, DEFAULT_PASSPHRASE_FOR_MNEMONIC, Utils.currentTimeSeconds()); } /** @@ -154,8 +155,8 @@ public class DeterministicKeyChain implements EncryptableKeyChain { * if the starting seed is the same. You should provide the creation time in seconds since the UNIX epoch for the * seed: this lets us know from what part of the chain we can expect to see derived keys appear. */ - public DeterministicKeyChain(byte[] seed, long seedCreationTimeSecs) { - this(new DeterministicSeed(seed, seedCreationTimeSecs)); + public DeterministicKeyChain(byte[] entropy, String passphrase, long seedCreationTimeSecs) { + this(new DeterministicSeed(entropy, passphrase, seedCreationTimeSecs)); } /** @@ -224,7 +225,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain { this.seed = seed; basicKeyChain = new BasicKeyChain(crypter); if (!seed.isEncrypted()) { - rootKey = HDKeyDerivation.createMasterPrivateKey(checkNotNull(seed.getSecretBytes())); + rootKey = HDKeyDerivation.createMasterPrivateKey(checkNotNull(seed.getSeedBytes())); rootKey.setCreationTimeSeconds(seed.getCreationTimeSeconds()); initializeHierarchyUnencrypted(rootKey); } else { @@ -524,14 +525,9 @@ public class DeterministicKeyChain implements EncryptableKeyChain { // data (handling encryption along the way), and letting us patch it up with the extra data we care about. LinkedList entries = newLinkedList(); if (seed != null) { - Protos.Key.Builder seedEntry = BasicKeyChain.serializeEncryptableItem(seed); - seedEntry.setType(Protos.Key.Type.DETERMINISTIC_ROOT_SEED); - entries.add(seedEntry.build()); - if (seed.hasMnemonicCode()) { - Protos.Key.Builder mnemonicEntry = BasicKeyChain.serializeEncryptableItem(seed.getMnemonicEncryptableItem()); - mnemonicEntry.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC); - entries.add(mnemonicEntry.build()); - } + Protos.Key.Builder mnemonicEntry = BasicKeyChain.serializeEncryptableItem(seed); + mnemonicEntry.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC); + entries.add(mnemonicEntry.build()); } Map keys = basicKeyChain.serializeToEditableProtobufs(); for (Map.Entry entry : keys.entrySet()) { @@ -577,18 +573,6 @@ public class DeterministicKeyChain implements EncryptableKeyChain { for (Protos.Key key : keys) { final Protos.Key.Type t = key.getType(); if (t == Protos.Key.Type.DETERMINISTIC_MNEMONIC) { - checkState(chain == null); - checkState(seed != null); - if (key.hasSecretBytes()) { - seed.setMnemonicCode(key.getSecretBytes().toByteArray()); - } else if (key.hasEncryptedData()) { - EncryptedData data = new EncryptedData(key.getEncryptedData().getInitialisationVector().toByteArray(), - key.getEncryptedData().getEncryptedPrivateKey().toByteArray()); - seed.setEncryptedMnemonicCode(data); - } else { - throw new UnreadableWalletException("Malformed key proto: " + key.toString()); - } - } else if (t == Protos.Key.Type.DETERMINISTIC_ROOT_SEED) { if (chain != null) { checkState(lookaheadSize >= 0); chain.setLookaheadSize(lookaheadSize); @@ -597,8 +581,9 @@ public class DeterministicKeyChain implements EncryptableKeyChain { chain = null; } long timestamp = key.getCreationTimestamp() / 1000; + String passphrase = DEFAULT_PASSPHRASE_FOR_MNEMONIC; // FIXME allow non-empty passphrase if (key.hasSecretBytes()) { - seed = new DeterministicSeed(key.getSecretBytes().toByteArray(), timestamp); + seed = new DeterministicSeed(key.getSecretBytes().toStringUtf8(), passphrase, timestamp); } else if (key.hasEncryptedData()) { EncryptedData data = new EncryptedData(key.getEncryptedData().getInitialisationVector().toByteArray(), key.getEncryptedData().getEncryptedPrivateKey().toByteArray()); @@ -607,7 +592,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain { throw new UnreadableWalletException("Malformed key proto: " + key.toString()); } if (log.isDebugEnabled()) - log.debug("Deserializing: DETERMINISTIC_ROOT_SEED: {}", seed); + log.debug("Deserializing: DETERMINISTIC_MNEMONIC: {}", seed); } else if (t == Protos.Key.Type.DETERMINISTIC_KEY) { if (!key.hasDeterministicKey()) throw new UnreadableWalletException("Deterministic key missing extra data: " + key.toString()); @@ -749,7 +734,8 @@ public class DeterministicKeyChain implements EncryptableKeyChain { public DeterministicKeyChain toDecrypted(KeyParameter aesKey) { checkState(getKeyCrypter() != null, "Key chain not encrypted"); checkState(seed.isEncrypted()); - DeterministicSeed decSeed = seed.decrypt(getKeyCrypter(), aesKey); + String passphrase = DEFAULT_PASSPHRASE_FOR_MNEMONIC; // FIXME allow non-empty passphrase + DeterministicSeed decSeed = seed.decrypt(getKeyCrypter(), passphrase, aesKey); DeterministicKeyChain chain = new DeterministicKeyChain(decSeed); // Now double check that the keys match to catch the case where the key is wrong but padding didn't catch it. if (!chain.getWatchingKey().getPubKeyPoint().equals(getWatchingKey().getPubKeyPoint())) diff --git a/core/src/main/java/com/google/bitcoin/wallet/DeterministicSeed.java b/core/src/main/java/com/google/bitcoin/wallet/DeterministicSeed.java index 55c56aba7..9e5697854 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/DeterministicSeed.java +++ b/core/src/main/java/com/google/bitcoin/wallet/DeterministicSeed.java @@ -30,7 +30,6 @@ import javax.annotation.Nullable; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.SecureRandom; -import java.util.Arrays; import java.util.List; import static com.google.bitcoin.core.Utils.HEX; @@ -49,8 +48,7 @@ public class DeterministicSeed implements EncryptableItem { public static final int MAX_SEED_ENTROPY_BITS = 512; public static final String UTF_8 = "UTF-8"; - @Nullable private final byte[] unencryptedSeed; - @Nullable private final EncryptedData encryptedSeed; + @Nullable private final byte[] seed; @Nullable private List mnemonicCode; @Nullable private EncryptedData encryptedMnemonicCode; private final long creationTimeSeconds; @@ -69,33 +67,24 @@ public class DeterministicSeed implements EncryptableItem { } } - DeterministicSeed(byte[] unencryptedSeed, List mnemonic, long creationTimeSeconds) { - this.unencryptedSeed = checkNotNull(unencryptedSeed); - this.encryptedSeed = null; - this.mnemonicCode = mnemonic; + DeterministicSeed(String mnemonicCode, String passphrase, long creationTimeSeconds) throws UnreadableWalletException { + this(decodeMnemonicCode(mnemonicCode), passphrase, creationTimeSeconds); + } + + DeterministicSeed(byte[] seed, List mnemonic, long creationTimeSeconds) { + this.seed = checkNotNull(seed); + this.mnemonicCode = checkNotNull(mnemonic); this.encryptedMnemonicCode = null; this.creationTimeSeconds = creationTimeSeconds; } - /** - * Constructs a seed from bytes. The mnemonic phrase is unknown. - */ - public DeterministicSeed(byte[] unencryptedSeed, long creationTimeSeconds) { - this(unencryptedSeed, null, creationTimeSeconds); - } - - DeterministicSeed(EncryptedData encryptedSeed, EncryptedData encryptedMnemonic, long creationTimeSeconds) { - this.unencryptedSeed = null; + DeterministicSeed(EncryptedData encryptedMnemonic, long creationTimeSeconds) { + this.seed = null; this.mnemonicCode = null; - this.encryptedSeed = checkNotNull(encryptedSeed); - this.encryptedMnemonicCode = encryptedMnemonic; + this.encryptedMnemonicCode = checkNotNull(encryptedMnemonic); this.creationTimeSeconds = creationTimeSeconds; } - DeterministicSeed(EncryptedData encryptedSeed, long creationTimeSeconds) { - this(encryptedSeed, null, creationTimeSeconds); - } - /** * Constructs a seed from a BIP 39 mnemonic code. See {@link com.google.bitcoin.crypto.MnemonicCode} for more * details on this scheme. @@ -116,22 +105,33 @@ public class DeterministicSeed implements EncryptableItem { * @param creationTimeSeconds When the seed was originally created, UNIX time. */ public DeterministicSeed(SecureRandom random, int bits, String passphrase, long creationTimeSeconds) { - byte[] entropy = getEntropy(random, bits); + this(getEntropy(random, bits), passphrase, creationTimeSeconds); + } + + /** + * Constructs a seed from a BIP 39 mnemonic code. See {@link com.google.bitcoin.crypto.MnemonicCode} for more + * details on this scheme. + * @param entropy entropy bits, length must be divisible by 32 + * @param passphrase A user supplied passphrase, or an empty string if there is no passphrase + * @param creationTimeSeconds When the seed was originally created, UNIX time. + */ + public DeterministicSeed(byte[] entropy, String passphrase, long creationTimeSeconds) { + Preconditions.checkArgument(entropy.length % 4 == 0, "entropy size in bits not divisible by 32"); + Preconditions.checkArgument(entropy.length * 8 >= DEFAULT_SEED_ENTROPY_BITS, "entropy size too small"); + try { this.mnemonicCode = getCachedMnemonicCodec().toMnemonic(entropy); } catch (MnemonicException.MnemonicLengthException e) { // cannot happen throw new RuntimeException(e); } - this.unencryptedSeed = getCachedMnemonicCodec().toSeed(mnemonicCode, passphrase); - this.encryptedSeed = null; + this.seed = getCachedMnemonicCodec().toSeed(mnemonicCode, passphrase); + this.encryptedMnemonicCode = null; this.creationTimeSeconds = creationTimeSeconds; } private static byte[] getEntropy(SecureRandom random, int bits) { - Preconditions.checkArgument(bits >= DEFAULT_SEED_ENTROPY_BITS, "requested entropy size too small"); Preconditions.checkArgument(bits <= MAX_SEED_ENTROPY_BITS, "requested entropy size too large"); - Preconditions.checkArgument(bits % 32 == 0, "requested entropy size not divisible by 32"); byte[] seed = new byte[bits / 8]; random.nextBytes(seed); @@ -140,8 +140,8 @@ public class DeterministicSeed implements EncryptableItem { @Override public boolean isEncrypted() { - checkState(unencryptedSeed != null || encryptedSeed != null); - return encryptedSeed != null; + checkState(mnemonicCode != null || encryptedMnemonicCode != null); + return encryptedMnemonicCode != null; } @Override @@ -156,8 +156,8 @@ public class DeterministicSeed implements EncryptableItem { /** Returns the seed as hex or null if encrypted. */ @Nullable public String toHexString() { - if (unencryptedSeed != null) - return HEX.encode(unencryptedSeed); + if (seed != null) + return HEX.encode(seed); else return null; } @@ -165,13 +165,17 @@ public class DeterministicSeed implements EncryptableItem { @Nullable @Override public byte[] getSecretBytes() { - return unencryptedSeed; + return getMnemonicAsBytes(); + } + + public byte[] getSeedBytes() { + return seed; } @Nullable @Override public EncryptedData getEncryptedData() { - return encryptedSeed; + return encryptedMnemonicCode; } @Override @@ -184,43 +188,11 @@ public class DeterministicSeed implements EncryptableItem { return creationTimeSeconds; } - public EncryptableItem getMnemonicEncryptableItem() { - return new EncryptableItem() { - @Override - public boolean isEncrypted() { - return DeterministicSeed.this.isEncrypted(); - } - - @Nullable - @Override - public byte[] getSecretBytes() { - return getMnemonicAsBytes(); - } - - @Nullable - @Override - public EncryptedData getEncryptedData() { - return encryptedMnemonicCode; - } - - @Override - public Protos.Wallet.EncryptionType getEncryptionType() { - return Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES; - } - - @Override - public long getCreationTimeSeconds() { - return creationTimeSeconds; - } - }; - } - public DeterministicSeed encrypt(KeyCrypter keyCrypter, KeyParameter aesKey) { - checkState(encryptedSeed == null, "Trying to encrypt seed twice"); - checkState(unencryptedSeed != null, "Seed bytes missing so cannot encrypt"); - EncryptedData seed = keyCrypter.encrypt(unencryptedSeed, aesKey); - EncryptedData mnemonic = (mnemonicCode != null) ? keyCrypter.encrypt(getMnemonicAsBytes(), aesKey) : null; - return new DeterministicSeed(seed, mnemonic, creationTimeSeconds); + checkState(encryptedMnemonicCode == null, "Trying to encrypt seed twice"); + checkState(mnemonicCode != null, "Mnemonic missing so cannot encrypt"); + EncryptedData mnemonic = keyCrypter.encrypt(getMnemonicAsBytes(), aesKey); + return new DeterministicSeed(mnemonic, creationTimeSeconds); } private byte[] getMnemonicAsBytes() { @@ -231,19 +203,17 @@ public class DeterministicSeed implements EncryptableItem { } } - public DeterministicSeed decrypt(KeyCrypter crypter, KeyParameter aesKey) { + public DeterministicSeed decrypt(KeyCrypter crypter, String passphrase, KeyParameter aesKey) { checkState(isEncrypted()); - checkNotNull(encryptedSeed); - byte[] seed = crypter.decrypt(encryptedSeed, aesKey); + checkNotNull(encryptedMnemonicCode); List mnemonic = null; try { - if (encryptedMnemonicCode != null) - mnemonic = decodeMnemonicCode(crypter.decrypt(encryptedMnemonicCode, aesKey)); + mnemonic = decodeMnemonicCode(crypter.decrypt(encryptedMnemonicCode, aesKey)); } catch (UnreadableWalletException e) { // TODO what is the best way to handle this exception? throw new RuntimeException(e); } - return new DeterministicSeed(seed, mnemonic, creationTimeSeconds); + return new DeterministicSeed(mnemonic, passphrase, creationTimeSeconds); } @Override @@ -254,11 +224,11 @@ public class DeterministicSeed implements EncryptableItem { DeterministicSeed seed = (DeterministicSeed) o; if (creationTimeSeconds != seed.creationTimeSeconds) return false; - if (encryptedSeed != null) { - if (seed.encryptedSeed == null) return false; - if (!encryptedSeed.equals(seed.encryptedSeed)) return false; + if (encryptedMnemonicCode != null) { + if (seed.encryptedMnemonicCode == null) return false; + if (!encryptedMnemonicCode.equals(seed.encryptedMnemonicCode)) return false; } else { - if (!Arrays.equals(unencryptedSeed, seed.unencryptedSeed)) return false; + if (!mnemonicCode.equals(seed.mnemonicCode)) return false; } return true; @@ -266,7 +236,7 @@ public class DeterministicSeed implements EncryptableItem { @Override public int hashCode() { - int result = encryptedSeed != null ? encryptedSeed.hashCode() : Arrays.hashCode(unencryptedSeed); + int result = encryptedMnemonicCode != null ? encryptedMnemonicCode.hashCode() : mnemonicCode.hashCode(); result = 31 * result + (int) (creationTimeSeconds ^ (creationTimeSeconds >>> 32)); return result; } @@ -282,28 +252,17 @@ public class DeterministicSeed implements EncryptableItem { getCachedMnemonicCodec().check(mnemonicCode); } + byte[] getEntropyBytes() throws MnemonicException { + return getCachedMnemonicCodec().toEntropy(mnemonicCode); + } + /** Get the mnemonic code, or null if unknown. */ @Nullable public List getMnemonicCode() { return mnemonicCode; } - /** Set encrypted mnemonic code. Used by protobuf deserializer. */ - public void setEncryptedMnemonicCode(EncryptedData encryptedMnemonicCode) { - this.encryptedMnemonicCode = encryptedMnemonicCode; - } - - /** Set mnemonic code from UTF-8 encoded bytes. */ - public void setMnemonicCode(@Nullable byte[] mnemonicCode) throws UnreadableWalletException { - this.mnemonicCode = decodeMnemonicCode(mnemonicCode); - } - - /** Whether the mnemonic code is known for this seed. */ - public boolean hasMnemonicCode() { - return mnemonicCode != null || encryptedMnemonicCode != null; - } - - private List decodeMnemonicCode(byte[] mnemonicCode) throws UnreadableWalletException { + private static List decodeMnemonicCode(byte[] mnemonicCode) throws UnreadableWalletException { String code = null; try { code = new String(mnemonicCode, "UTF-8"); @@ -312,4 +271,8 @@ public class DeterministicSeed implements EncryptableItem { } return Splitter.on(" ").splitToList(code); } + + private static List decodeMnemonicCode(String mnemonicCode) { + return Splitter.on(" ").splitToList(mnemonicCode); + } } diff --git a/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java b/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java index d450e3575..5ea3d297c 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java +++ b/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java @@ -731,15 +731,16 @@ public class KeyChainGroup { } log.info("Auto-upgrading pre-HD wallet using oldest non-rotating private key"); - byte[] seed = checkNotNull(keyToUse.getSecretBytes()); + byte[] entropy = checkNotNull(keyToUse.getSecretBytes()); // Private keys should be at least 128 bits long. - checkState(seed.length >= DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); + checkState(entropy.length >= DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); // We reduce the entropy here to 128 bits because people like to write their seeds down on paper, and 128 // bits should be sufficient forever unless the laws of the universe change or ECC is broken; in either case // we all have bigger problems. - seed = Arrays.copyOfRange(seed, 0, DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); // final argument is exclusive range. - checkState(seed.length == DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); - DeterministicKeyChain chain = new DeterministicKeyChain(seed, keyToUse.getCreationTimeSeconds()); + entropy = Arrays.copyOfRange(entropy, 0, DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); // final argument is exclusive range. + checkState(entropy.length == DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8); + String passphrase = ""; // FIXME allow non-empty passphrase + DeterministicKeyChain chain = new DeterministicKeyChain(entropy, passphrase, keyToUse.getCreationTimeSeconds()); if (aesKey != null) { chain = chain.toEncrypted(checkNotNull(basic.getKeyCrypter()), aesKey); } diff --git a/core/src/main/java/org/bitcoinj/wallet/Protos.java b/core/src/main/java/org/bitcoinj/wallet/Protos.java index afa1fe0c2..56e3c7941 100644 --- a/core/src/main/java/org/bitcoinj/wallet/Protos.java +++ b/core/src/main/java/org/bitcoinj/wallet/Protos.java @@ -2526,15 +2526,15 @@ public final class Protos { */ ENCRYPTED_SCRYPT_AES(1, 2), /** - * DETERMINISTIC_ROOT_SEED = 3; + * DETERMINISTIC_MNEMONIC = 3; * *
        **
-       * Not really a key, but rather contains the seed for a deterministic key hierarchy in the private_key field.
+       * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field.
        * The label and public_key fields are missing. Creation timestamp will exist.
        * 
*/ - DETERMINISTIC_ROOT_SEED(2, 3), + DETERMINISTIC_MNEMONIC(2, 3), /** * DETERMINISTIC_KEY = 4; * @@ -2548,17 +2548,6 @@ public final class Protos { * */ DETERMINISTIC_KEY(3, 4), - /** - * DETERMINISTIC_MNEMONIC = 5; - * - *
-       **
-       * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field.
-       * The label and public_key fields are missing. Creation timestamp will exist.
-       * Must be immediately after DETERMINISTIC_KEY
-       * 
- */ - DETERMINISTIC_MNEMONIC(4, 5), ; /** @@ -2578,15 +2567,15 @@ public final class Protos { */ public static final int ENCRYPTED_SCRYPT_AES_VALUE = 2; /** - * DETERMINISTIC_ROOT_SEED = 3; + * DETERMINISTIC_MNEMONIC = 3; * *
        **
-       * Not really a key, but rather contains the seed for a deterministic key hierarchy in the private_key field.
+       * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field.
        * The label and public_key fields are missing. Creation timestamp will exist.
        * 
*/ - public static final int DETERMINISTIC_ROOT_SEED_VALUE = 3; + public static final int DETERMINISTIC_MNEMONIC_VALUE = 3; /** * DETERMINISTIC_KEY = 4; * @@ -2600,17 +2589,6 @@ public final class Protos { * */ public static final int DETERMINISTIC_KEY_VALUE = 4; - /** - * DETERMINISTIC_MNEMONIC = 5; - * - *
-       **
-       * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field.
-       * The label and public_key fields are missing. Creation timestamp will exist.
-       * Must be immediately after DETERMINISTIC_KEY
-       * 
- */ - public static final int DETERMINISTIC_MNEMONIC_VALUE = 5; public final int getNumber() { return value; } @@ -2619,9 +2597,8 @@ public final class Protos { switch (value) { case 1: return ORIGINAL; case 2: return ENCRYPTED_SCRYPT_AES; - case 3: return DETERMINISTIC_ROOT_SEED; + case 3: return DETERMINISTIC_MNEMONIC; case 4: return DETERMINISTIC_KEY; - case 5: return DETERMINISTIC_MNEMONIC; default: return null; } } @@ -16184,67 +16161,66 @@ public final class Protos { "ey\030\002 \002(\014\"y\n\020DeterministicKey\022\022\n\nchain_co" + "de\030\001 \002(\014\022\014\n\004path\030\002 \003(\r\022\026\n\016issued_subkeys" + "\030\003 \001(\r\022\026\n\016lookahead_size\030\004 \001(\r\022\023\n\013isFoll" + - "owing\030\005 \001(\010\"\336\002\n\003Key\022\036\n\004type\030\001 \002(\0162\020.wall" + + "owing\030\005 \001(\010\"\301\002\n\003Key\022\036\n\004type\030\001 \002(\0162\020.wall" + "et.Key.Type\022\024\n\014secret_bytes\030\002 \001(\014\022-\n\016enc" + "rypted_data\030\006 \001(\0132\025.wallet.EncryptedData", "\022\022\n\npublic_key\030\003 \001(\014\022\r\n\005label\030\004 \001(\t\022\032\n\022c" + "reation_timestamp\030\005 \001(\003\0223\n\021deterministic" + - "_key\030\007 \001(\0132\030.wallet.DeterministicKey\"~\n\004" + + "_key\030\007 \001(\0132\030.wallet.DeterministicKey\"a\n\004" + "Type\022\014\n\010ORIGINAL\020\001\022\030\n\024ENCRYPTED_SCRYPT_A" + - "ES\020\002\022\033\n\027DETERMINISTIC_ROOT_SEED\020\003\022\025\n\021DET" + - "ERMINISTIC_KEY\020\004\022\032\n\026DETERMINISTIC_MNEMON" + - "IC\020\005\"5\n\006Script\022\017\n\007program\030\001 \002(\014\022\032\n\022creat" + - "ion_timestamp\030\002 \002(\003\"\222\001\n\020TransactionInput" + - "\022\"\n\032transaction_out_point_hash\030\001 \002(\014\022#\n\033" + - "transaction_out_point_index\030\002 \002(\r\022\024\n\014scr", - "ipt_bytes\030\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\022\r\n\005val" + - "ue\030\005 \001(\003\"\177\n\021TransactionOutput\022\r\n\005value\030\001" + - " \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by_t" + - "ransaction_hash\030\003 \001(\014\022\"\n\032spent_by_transa" + - "ction_index\030\004 \001(\005\"\234\003\n\025TransactionConfide" + - "nce\0220\n\004type\030\001 \001(\0162\".wallet.TransactionCo" + - "nfidence.Type\022\032\n\022appeared_at_height\030\002 \001(" + - "\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005dep" + - "th\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003\022)\n\014broadcast" + - "_by\030\006 \003(\0132\023.wallet.PeerAddress\0224\n\006source", - "\030\007 \001(\0162$.wallet.TransactionConfidence.So" + - "urce\"O\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022" + - "\013\n\007PENDING\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004D" + - "EAD\020\004\"A\n\006Source\022\022\n\016SOURCE_UNKNOWN\020\000\022\022\n\016S" + - "OURCE_NETWORK\020\001\022\017\n\013SOURCE_SELF\020\002\"\236\004\n\013Tra" + - "nsaction\022\017\n\007version\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022" + - "&\n\004pool\030\003 \001(\0162\030.wallet.Transaction.Pool\022" + - "\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223" + - "\n\021transaction_input\030\006 \003(\0132\030.wallet.Trans" + - "actionInput\0225\n\022transaction_output\030\007 \003(\0132", - "\031.wallet.TransactionOutput\022\022\n\nblock_hash" + - "\030\010 \003(\014\022 \n\030block_relativity_offsets\030\013 \003(\005" + - "\0221\n\nconfidence\030\t \001(\0132\035.wallet.Transactio" + - "nConfidence\0225\n\007purpose\030\n \001(\0162\033.wallet.Tr" + - "ansaction.Purpose:\007UNKNOWN\"Y\n\004Pool\022\013\n\007UN" + - "SPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DEAD" + - "\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\":\n" + - "\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_PAYMENT\020\001\022" + - "\020\n\014KEY_ROTATION\020\002\"N\n\020ScryptParameters\022\014\n" + - "\004salt\030\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005", - ":\0018\022\014\n\001p\030\004 \001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002" + - "(\t\022\014\n\004data\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\" \n\003T" + - "ag\022\013\n\003tag\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\"\261\004\n\006Wallet" + - "\022\032\n\022network_identifier\030\001 \002(\t\022\034\n\024last_see" + - "n_block_hash\030\002 \001(\014\022\036\n\026last_seen_block_he" + - "ight\030\014 \001(\r\022!\n\031last_seen_block_time_secs\030" + - "\016 \001(\003\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013trans" + - "action\030\004 \003(\0132\023.wallet.Transaction\022&\n\016wat" + - "ched_script\030\017 \003(\0132\016.wallet.Script\022C\n\017enc" + - "ryption_type\030\005 \001(\0162\035.wallet.Wallet.Encry", - "ptionType:\013UNENCRYPTED\0227\n\025encryption_par" + - "ameters\030\006 \001(\0132\030.wallet.ScryptParameters\022" + - "\022\n\007version\030\007 \001(\005:\0011\022$\n\textension\030\n \003(\0132\021" + - ".wallet.Extension\022\023\n\013description\030\013 \001(\t\022\031" + - "\n\021key_rotation_time\030\r \001(\004\022\031\n\004tags\030\020 \003(\0132" + - "\013.wallet.Tag\";\n\016EncryptionType\022\017\n\013UNENCR" + - "YPTED\020\001\022\030\n\024ENCRYPTED_SCRYPT_AES\020\002B\035\n\023org" + - ".bitcoinj.walletB\006Protos" + "ES\020\002\022\032\n\026DETERMINISTIC_MNEMONIC\020\003\022\025\n\021DETE" + + "RMINISTIC_KEY\020\004\"5\n\006Script\022\017\n\007program\030\001 \002" + + "(\014\022\032\n\022creation_timestamp\030\002 \002(\003\"\222\001\n\020Trans" + + "actionInput\022\"\n\032transaction_out_point_has" + + "h\030\001 \002(\014\022#\n\033transaction_out_point_index\030\002" + + " \002(\r\022\024\n\014script_bytes\030\003 \002(\014\022\020\n\010sequence\030\004", + " \001(\r\022\r\n\005value\030\005 \001(\003\"\177\n\021TransactionOutput" + + "\022\r\n\005value\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n" + + "\031spent_by_transaction_hash\030\003 \001(\014\022\"\n\032spen" + + "t_by_transaction_index\030\004 \001(\005\"\234\003\n\025Transac" + + "tionConfidence\0220\n\004type\030\001 \001(\0162\".wallet.Tr" + + "ansactionConfidence.Type\022\032\n\022appeared_at_" + + "height\030\002 \001(\005\022\036\n\026overriding_transaction\030\003" + + " \001(\014\022\r\n\005depth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003\022)" + + "\n\014broadcast_by\030\006 \003(\0132\023.wallet.PeerAddres" + + "s\0224\n\006source\030\007 \001(\0162$.wallet.TransactionCo", + "nfidence.Source\"O\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010" + + "BUILDING\020\001\022\013\n\007PENDING\020\002\022\025\n\021NOT_IN_BEST_C" + + "HAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022\n\016SOURCE_UNK" + + "NOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_SEL" + + "F\020\002\"\236\004\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n\004" + + "hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Transa" + + "ction.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdated" + + "_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030.w" + + "allet.TransactionInput\0225\n\022transaction_ou" + + "tput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022\n", + "\nblock_hash\030\010 \003(\014\022 \n\030block_relativity_of" + + "fsets\030\013 \003(\005\0221\n\nconfidence\030\t \001(\0132\035.wallet" + + ".TransactionConfidence\0225\n\007purpose\030\n \001(\0162" + + "\033.wallet.Transaction.Purpose:\007UNKNOWN\"Y\n" + + "\004Pool\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIV" + + "E\020\002\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_IN" + + "ACTIVE\020\022\":\n\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER" + + "_PAYMENT\020\001\022\020\n\014KEY_ROTATION\020\002\"N\n\020ScryptPa" + + "rameters\022\014\n\004salt\030\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384" + + "\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 \001(\005:\0011\"8\n\tExtensio", + "n\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021\n\tmandatory" + + "\030\003 \002(\010\" \n\003Tag\022\013\n\003tag\030\001 \002(\t\022\014\n\004data\030\002 \002(\014" + + "\"\261\004\n\006Wallet\022\032\n\022network_identifier\030\001 \002(\t\022" + + "\034\n\024last_seen_block_hash\030\002 \001(\014\022\036\n\026last_se" + + "en_block_height\030\014 \001(\r\022!\n\031last_seen_block" + + "_time_secs\030\016 \001(\003\022\030\n\003key\030\003 \003(\0132\013.wallet.K" + + "ey\022(\n\013transaction\030\004 \003(\0132\023.wallet.Transac" + + "tion\022&\n\016watched_script\030\017 \003(\0132\016.wallet.Sc" + + "ript\022C\n\017encryption_type\030\005 \001(\0162\035.wallet.W" + + "allet.EncryptionType:\013UNENCRYPTED\0227\n\025enc", + "ryption_parameters\030\006 \001(\0132\030.wallet.Scrypt" + + "Parameters\022\022\n\007version\030\007 \001(\005:\0011\022$\n\textens" + + "ion\030\n \003(\0132\021.wallet.Extension\022\023\n\013descript" + + "ion\030\013 \001(\t\022\031\n\021key_rotation_time\030\r \001(\004\022\031\n\004" + + "tags\030\020 \003(\0132\013.wallet.Tag\";\n\016EncryptionTyp" + + "e\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCRYPTED_SCRYPT_A" + + "ES\020\002B\035\n\023org.bitcoinj.walletB\006Protos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { diff --git a/core/src/test/java/com/google/bitcoin/wallet/DeterministicKeyChainTest.java b/core/src/test/java/com/google/bitcoin/wallet/DeterministicKeyChainTest.java index af191beab..9ed65a3be 100644 --- a/core/src/test/java/com/google/bitcoin/wallet/DeterministicKeyChainTest.java +++ b/core/src/test/java/com/google/bitcoin/wallet/DeterministicKeyChainTest.java @@ -24,7 +24,6 @@ import com.google.bitcoin.store.UnreadableWalletException; import com.google.bitcoin.utils.BriefLogFormatter; import com.google.bitcoin.utils.Threading; import com.google.common.base.Charsets; -import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.io.Resources; import org.bitcoinj.wallet.Protos; @@ -41,7 +40,7 @@ import static org.junit.Assert.*; public class DeterministicKeyChainTest { private DeterministicKeyChain chain; - private final byte[] SEED = Sha256Hash.create("don't use a string seed like this in real life".getBytes()).getBytes(); + private final byte[] ENTROPY = Sha256Hash.create("don't use a string seed like this in real life".getBytes()).getBytes(); @Before public void setup() { @@ -49,7 +48,7 @@ public class DeterministicKeyChainTest { // You should use a random seed instead. The secs constant comes from the unit test file, so we can compare // serialized data properly. long secs = 1389353062L; - chain = new DeterministicKeyChain(SEED, secs); + chain = new DeterministicKeyChain(ENTROPY, "", secs); chain.setLookaheadSize(10); assertEquals(secs, checkNotNull(chain.getSeed()).getCreationTimeSeconds()); } @@ -59,16 +58,16 @@ public class DeterministicKeyChainTest { ECKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); ECKey key2 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); - final Address address = new Address(UnitTestParams.get(), "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa"); + final Address address = new Address(UnitTestParams.get(), "n1bQNoEx8uhmCzzA5JPG6sFdtsUQhwiQJV"); assertEquals(address, key1.toAddress(UnitTestParams.get())); - assertEquals("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X", key2.toAddress(UnitTestParams.get()).toString()); + assertEquals("mnHUcqUVvrfi5kAaXJDQzBb9HsWs78b42R", key2.toAddress(UnitTestParams.get()).toString()); assertEquals(key1, chain.findKeyFromPubHash(address.getHash160())); assertEquals(key2, chain.findKeyFromPubKey(key2.getPubKey())); key1.sign(Sha256Hash.ZERO_HASH); ECKey key3 = chain.getKey(KeyChain.KeyPurpose.CHANGE); - assertEquals("mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn", key3.toAddress(UnitTestParams.get()).toString()); + assertEquals("mqumHgVDqNzuXNrszBmi7A2UpmwaPMx4HQ", key3.toAddress(UnitTestParams.get()).toString()); key3.sign(Sha256Hash.ZERO_HASH); } @@ -77,7 +76,7 @@ public class DeterministicKeyChainTest { // Check that we get the right events at the right time. final List> listenerKeys = Lists.newArrayList(); long secs = 1389353062L; - chain = new DeterministicKeyChain(SEED, secs); + chain = new DeterministicKeyChain(ENTROPY, "", secs); chain.addEventListener(new AbstractKeyChainEventListener() { @Override public void onKeysAdded(List keys) { @@ -219,7 +218,7 @@ public class DeterministicKeyChainTest { DeterministicKey watchingKey = chain.getWatchingKey(); final String pub58 = watchingKey.serializePubB58(); - assertEquals("xpub68KFnj3bqUx1s7mHejLDBPywCAKdJEu1b49uniEEn2WSbHmZ7xbLqFTjJbtx1LUcAt1DwhoqWHmo2s5WMJp6wi38CiF2hYD49qVViKVvAoi", pub58); + assertEquals("xpub69KR9epSNBM59KLuasxMU5CyKytMJjBP5HEZ5p8YoGUCpM6cM9hqxB9DDPCpUUtqmw5duTckvPfwpoWGQUFPmRLpxs5jYiTf2u6xRMcdhDf", pub58); watchingKey = DeterministicKey.deserializeB58(null, pub58); watchingKey.setCreationTimeSeconds(100000); chain = DeterministicKeyChain.watch(watchingKey); diff --git a/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java b/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java index 79955b08e..987126e6e 100644 --- a/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java +++ b/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java @@ -56,8 +56,8 @@ public class KeyChainGroupTest { } private KeyChainGroup createMarriedKeyChainGroup() { - byte[] seedBytes = Sha256Hash.create("don't use a seed like this in real life".getBytes()).getBytes(); - DeterministicSeed seed = new DeterministicSeed(seedBytes, MnemonicCode.BIP39_STANDARDISATION_TIME_SECS); + byte[] entropy = Sha256Hash.create("don't use a seed like this in real life".getBytes()).getBytes(); + DeterministicSeed seed = new DeterministicSeed(entropy, "", MnemonicCode.BIP39_STANDARDISATION_TIME_SECS); KeyChainGroup group = new KeyChainGroup(params, seed, ImmutableList.of(watchingAccountKey)); group.setLookaheadSize(LOOKAHEAD_SIZE); group.getActiveKeyChain(); @@ -380,25 +380,25 @@ public class KeyChainGroupTest { @Test public void serialization() throws Exception { - assertEquals(INITIAL_KEYS + 2 /* for the seed */, group.serializeToProtobuf().size()); + assertEquals(INITIAL_KEYS + 1 /* for the seed */, group.serializeToProtobuf().size()); group = KeyChainGroup.fromProtobufUnencrypted(params, group.serializeToProtobuf()); group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key2 = group.freshKey(KeyChain.KeyPurpose.CHANGE); List protoKeys1 = group.serializeToProtobuf(); - assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 2 /* for the seed */ + 1, protoKeys1.size()); + assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 1, protoKeys1.size()); group.importKeys(new ECKey()); List protoKeys2 = group.serializeToProtobuf(); - assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 2 /* for the seed */ + 2, protoKeys2.size()); + assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size()); group = KeyChainGroup.fromProtobufUnencrypted(params, protoKeys1); - assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 2 /* for the seed */ + 1, protoKeys1.size()); + assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 1, protoKeys1.size()); assertTrue(group.hasKey(key1)); assertTrue(group.hasKey(key2)); assertEquals(key2, group.currentKey(KeyChain.KeyPurpose.CHANGE)); assertEquals(key1, group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS)); group = KeyChainGroup.fromProtobufUnencrypted(params, protoKeys2); - assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 2 /* for the seed */ + 2, protoKeys2.size()); + assertEquals(INITIAL_KEYS + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size()); assertTrue(group.hasKey(key1)); assertTrue(group.hasKey(key2)); @@ -505,7 +505,7 @@ public class KeyChainGroupTest { // Check we used the right (oldest) key despite backwards import order. byte[] truncatedBytes = Arrays.copyOfRange(key1.getSecretBytes(), 0, 16); - assertArrayEquals(seed1.getSecretBytes(), truncatedBytes); + assertArrayEquals(seed1.getEntropyBytes(), truncatedBytes); } @Test @@ -524,7 +524,7 @@ public class KeyChainGroupTest { assertNotNull(seed); // Check we used the right key: oldest non rotating. byte[] truncatedBytes = Arrays.copyOfRange(key2.getSecretBytes(), 0, 16); - assertArrayEquals(seed.getSecretBytes(), truncatedBytes); + assertArrayEquals(seed.getEntropyBytes(), truncatedBytes); } @Test @@ -548,9 +548,9 @@ public class KeyChainGroupTest { final DeterministicSeed deterministicSeed = group.getActiveKeyChain().getSeed(); assertNotNull(deterministicSeed); assertTrue(deterministicSeed.isEncrypted()); - byte[] seed = checkNotNull(group.getActiveKeyChain().toDecrypted(aesKey).getSeed()).getSecretBytes(); + byte[] entropy = checkNotNull(group.getActiveKeyChain().toDecrypted(aesKey).getSeed()).getEntropyBytes(); // Check we used the right key: oldest non rotating. byte[] truncatedBytes = Arrays.copyOfRange(key.getSecretBytes(), 0, 16); - assertArrayEquals(seed, truncatedBytes); + assertArrayEquals(entropy, truncatedBytes); } } 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 a45bb5777..f80dcc911 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 @@ -1,28 +1,28 @@ -type: DETERMINISTIC_ROOT_SEED -secret_bytes: "\004Q\316\005\330\376\353f!WHLL\a" creation_timestamp: 1389353062000 deterministic_key { - chain_code: ",\263\335\024\031\221c;~\325\326\272\367*\r+\032H\270\026\234\226\357\222i_VxP\200x\252" + chain_code: "XL\240FW\203\316\230\334\374J\003\357=\215\001\206\365\207Z\006m\334X`\236,;_\304\000^" } type: DETERMINISTIC_KEY -secret_bytes: "\364\r-u\037\337Sl\272\314\221L\306\356?\3505d\330\321_3W\234R#\035\273z\341x\275" -public_key: "\002LOV+\260\017\024lxz\021\236Xv\000X\324e\244\037\243\325\325f\003vs*]\260\340\035" +secret_bytes: "\354B\331\275;\000\254?\3428\006\220G\365\243\333s\260s\213R\313\307\377f\331B\351\327=\001\333" +public_key: "\002\357\\\252\376]\023\315\'\316`\317\362\032@\232\"\360\331\335\221] `\016,\351<\b\300\225\032m" deterministic_key { - chain_code: "\377\340\2459\230\210\367\361\362\205\267\244#\t#\360\215\221_\302v\315{\200Y\210\224\"\243\272\256\301" + chain_code: "\370\017\223\021O?.@gZ|\233j\3437\317q-\241!J \323\'\264s\203\314\321\v\346" path: 2147483648 } type: DETERMINISTIC_KEY -secret_bytes: "~\301G\035\221\b\024\023\275\211s\273\270\205/4\233ai\366~\006\341$lc\000\272\336\021\347\305" -public_key: "\002\264\r,\017e\213\016W\372\024W\215z\022C@+A\2720G\016\034\353\202\312\372\251\206\035r" +secret_bytes: "a\305j\001P\217Q\242\261.\353\367\315" deterministic_key { - chain_code: "\000Mm\373e\255\363\373\'\265A\003\247\320U\305\340\342\233\033\034\312zTR\006\347Yu\362b\366" + chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217" path: 2147483648 path: 0 issued_subkeys: 2 @@ -30,10 +30,10 @@ deterministic_key { } type: DETERMINISTIC_KEY -secret_bytes: "\"\273\024]\271iR\237\335\343HN\353\352\v\220\241\006\022\302\244W\033~\260HTtz\005\376F" -public_key: "\002\330b\034\023\320\217|!\271p\034\017p\330!\245\233j\376\b\316\373\231D\324\271d\217h\217\016^" +secret_bytes: "\f0\266\235\272\205\212:\265\372\214P\226\344\a{S0\354\250\210\316L\256;W\036\200t\347\343\246" +public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370" deterministic_key { - chain_code: "\367j\245\025U\265\346\v\234\275\343\rd\214q\004\232\253\312\222Hi\305\201\370`^\304\210\034p*" + chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311" path: 2147483648 path: 1 issued_subkeys: 1 @@ -41,207 +41,207 @@ deterministic_key { } type: DETERMINISTIC_KEY -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" +public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377" deterministic_key { - chain_code: "RS\20672^\r\265\fNCd\305\235\266\a\232\033\303\316\230\376FK\322\314\300}\335zk\016" + chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035" path: 2147483648 path: 0 path: 0 } type: DETERMINISTIC_KEY -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" +public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313" deterministic_key { - chain_code: ":JV\362\341\275\220\370r\031@\272\225,\307B\v\023\017\277\b\02000\261\225\026\355J\b\316G" + chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306" path: 2147483648 path: 0 path: 1 } type: DETERMINISTIC_KEY -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" +public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-" deterministic_key { - chain_code: "\005\2717\377\3625\362\017`\270\370k\301B\241C[\350\213\244m{L&C\244\250\200$\f\025\357" + chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324" path: 2147483648 path: 0 path: 2 } type: DETERMINISTIC_KEY -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" +public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215" deterministic_key { - chain_code: "$\211\377\t\276\033I!*\320\003\316\260Bl\r^ w\276\300\025\251\ak\317\342\034@9\204\374" + chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t" path: 2147483648 path: 0 path: 3 } type: DETERMINISTIC_KEY -public_key: "\003\273\222i0kH\005\313e\373\306c\021\340u\275\353\231\224i\333\357\017r\372\200\036PW\311\356," +public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m" deterministic_key { - chain_code: "f\315\357Y0\037\033\377)|\234\273\267\234\324\000\251\263#&\\\255tZ\313+\0003Hn\022" + chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P" path: 2147483648 path: 0 path: 4 } type: DETERMINISTIC_KEY -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" +public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV" deterministic_key { - chain_code: "\372\232\306\242\340P\251\037\227\222z\311\260\f\350 \2627@\223\247\333= \2118\331\344\006\236\362m" + chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215" path: 2147483648 path: 0 path: 5 } type: DETERMINISTIC_KEY -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" +public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X" deterministic_key { - chain_code: "\2714Rw\317\230\001\356h\203\216z\230xL~[lR\032\275\247\277\362r\333q\220\242`\206\275" + chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg" path: 2147483648 path: 0 path: 6 } type: DETERMINISTIC_KEY -public_key: "\002\361z\203\341\345\350\214L\272\262\301-8/\246xX\'\r\027\026#^M\a\313\277\356\354B\022" +public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355" deterministic_key { - chain_code: "\242\3452\270\275\321\363\206#\310\206\222\2359%tH\364\343\271\266\372I\204U\031Y\325CIbY" + chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313" path: 2147483648 path: 0 path: 7 } type: DETERMINISTIC_KEY -public_key: "\003l\021W\350G\026kc\225\213\307Rv1[p\270P\r\266T\275\021\b\270\335\'\270\254\307\242:" +public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b" deterministic_key { - chain_code: "\364E\240q\263\227Y\200\361q/\212X\343i\234\226\235\036+\n\036&\203(\341\002\235\270\021U\342" + chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224" path: 2147483648 path: 0 path: 8 } type: DETERMINISTIC_KEY -public_key: "\003KaP\210J\320\354\202\024#*#\323\276i\\\004\341\225\253qw_\235\371\370\316\315N\rZ\031" +public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419" deterministic_key { - chain_code: "\2561\251Rw\2434%\304\v]\020\220d\370\234<\217\214\306\363\361\033\262\204\265}#\224\333\255\031" + chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-" path: 2147483648 path: 0 path: 9 } type: DETERMINISTIC_KEY -public_key: "\003\250\371\347\214\240t\242\355\277\231\3351\227g\222\375\363[\326p9\244\032\305^}\003)\000\035\252E" +public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K" deterministic_key { - chain_code: "\362\203\2555\335\3013\037\361\200-\245i\225\024\322\274V#;\3157`$\360\206\332?/P]\034" + chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225" path: 2147483648 path: 0 path: 10 } type: DETERMINISTIC_KEY -public_key: "\002\263\220\a\311h`\216?m\375\232V\205\025zi,`\203\252{\323,&\247\304\263\006K\035j\261" +public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323" deterministic_key { - chain_code: "\251K\330\274\360\254q\267\005\3331\2716\277M\3544\352S\006\243\317\223\305Y\304\317\r#\233\362H" + chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200" path: 2147483648 path: 0 path: 11 } type: DETERMINISTIC_KEY -public_key: "\002\336\201guA0\314$\016\335\016xTY\237I\327Zx\217\365K,k\334g\211\202\3770\247X" +public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\" deterministic_key { - chain_code: "WV#4$\027\034m\023\353\235U\021,\327\303\327[\b\003\255$\024\243v\2306\276\230/\273\021" + chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330" path: 2147483648 path: 1 path: 0 } type: DETERMINISTIC_KEY -public_key: "\002\221\322\332>W&\00475\374\317jP\021\332[[\276\363\016\2636\322:\321\361\032!?q-\320" +public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;" deterministic_key { - chain_code: "\036\364!\212\223\235\037\333\346\215o\344MD4\303\206\215\327M\354.\210\201c\353\267\254\245\250\257\273" + chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313" path: 2147483648 path: 1 path: 1 } type: DETERMINISTIC_KEY -public_key: "\003\204\311|\002}\002\201IQ\003c\253\335Ay\220@3\210\001~\345L\216u\030\217\232\262m{\371" +public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000" deterministic_key { - chain_code: "\036\026\334\313\264\227\025Y\n\367X8\b\355F,\262h\2246\373\203M1\355\254>\320\r5M\r" + chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341" path: 2147483648 path: 1 path: 2 } type: DETERMINISTIC_KEY -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" +public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237" deterministic_key { - chain_code: "N_\376\r\372n\000\263\353\v\220Z\254\023\307z)M\243g\200L\305\tU\n\n\354+C\016\277" + chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#" path: 2147483648 path: 1 path: 3 } type: DETERMINISTIC_KEY -public_key: "\003\000\344v\304py\001-]ut\245\32027\265\367R\331\026o\v\372|\213b1\343\356\250#" +public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321" deterministic_key { - chain_code: "\030@\276\337|\300\303\255\262\374\001\222\023\240%\220\274\306=\242$\213\356\355URv2\210\257\350\201" + chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225" path: 2147483648 path: 1 path: 4 } type: DETERMINISTIC_KEY -public_key: "\002P\254\2652\374\234\312\250\325\300\212\367\217F\275~\370\200\270T\260\323\317\030\200\240\242" + chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266" path: 2147483648 path: 1 path: 5 } type: DETERMINISTIC_KEY -public_key: "\003\000\323\225^\225\032\275R\267\347\213\256\033-\252\302\322`%fL\326\bo\337\367c\232\241\310\354\330" +public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341" deterministic_key { - chain_code: "z\335|\370>\237\231\311ML3\360/\371\203\243#\037\3555\a%\231]4\213\310=\332\316\002\232" + chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232" path: 2147483648 path: 1 path: 6 } type: DETERMINISTIC_KEY -public_key: "\003\310\264dd\275\026\211\247\324\221\207edi\353\036\246\350\366\370\264\213\266\357_\332x}gI\367-" +public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230" deterministic_key { - chain_code: "\031\\\223*!\004\361\353|\347.\274\032P\275\337\n\224\233\230\216\2660\246\241\311\t>\255\016\313\204" + chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335" path: 2147483648 path: 1 path: 7 } type: DETERMINISTIC_KEY -public_key: "\003\226\253\321\200\001\346u\020_C9\nj\001} \212\027\341-f\f=\320~\311\200ck@\361\341" +public_key: "\003X\331\344\227G\366//\353[U" +public_key: "\003\307\273B\334\212\303\025r\212\264|\250c\204\\=\360w\335\300\353\266\273\3209\260nl3\271+" deterministic_key { - chain_code: "\306#\361\242\241\016-\346\341\330\325\331\352\231\220X\267y\207\302\020\353#\345\0033{\345\353\244\3362" + chain_code: "\345\365\034\261\316\2121R\226/+\267K\326C&\236\246],\224\001\220\347\334\351\223K\023\252\360\023" path: 2147483648 path: 1 path: 9 } type: DETERMINISTIC_KEY -public_key: "\003J\371[{Vs\232A\260\343\376!\265\a\031`\0239\277=jd\n\230\270\034\350#\302}x\334" +public_key: "\002+[\230[E\225\225R2\350X=\366\343\244\237\260\220J\311\376\200@\\\334\312y\212\276\223\350\267" deterministic_key { - chain_code: "c\330\261\301\001\215\307\v\374M\231B7!/x/\215\341\265\312\027b+%\032\304\322z\304`\254" + chain_code: "\250W]}O:@\t\016\311\016\335\016\271\260\327\261\237\030G\334\246\233\352t\266\\S\311\333m*" path: 2147483648 path: 1 path: 10 diff --git a/core/src/test/resources/com/google/bitcoin/wallet/watching-wallet-serialization.txt b/core/src/test/resources/com/google/bitcoin/wallet/watching-wallet-serialization.txt index a0b9c64bf..3b0471941 100644 --- a/core/src/test/resources/com/google/bitcoin/wallet/watching-wallet-serialization.txt +++ b/core/src/test/resources/com/google/bitcoin/wallet/watching-wallet-serialization.txt @@ -1,15 +1,15 @@ type: DETERMINISTIC_KEY -public_key: "\002LOV+\260\017\024lxz\021\236Xv\000X\324e\244\037\243\325\325f\003vs*]\260\340\035" +public_key: "\002\357\\\252\376]\023\315\'\316`\317\362\032@\232\"\360\331\335\221] `\016,\351<\b\300\225\032m" creation_timestamp: 100000000 deterministic_key { - chain_code: "\377\340\2459\230\210\367\361\362\205\267\244#\t#\360\215\221_\302v\315{\200Y\210\224\"\243\272\256\301" + chain_code: "\370\017\223\021O?.@gZ|\233j\3437\317q-\241!J \323\'\264s\203\314\321\v\346" path: 2147483648 } type: DETERMINISTIC_KEY -public_key: "\002\264\r,\017e\213\016W\372\024W\215z\022C@+A\2720G\016\034\353\202\312\372\251\206\035r" +public_key: "\002\361V\216\001\371p\270\212\272\236%\216\356o\025g\r\035>a\305j\001P\217Q\242\261.\353\367\315" deterministic_key { - chain_code: "\000Mm\373e\255\363\373\'\265A\003\247\320U\305\340\342\233\033\034\312zTR\006\347Yu\362b\366" + chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217" path: 2147483648 path: 0 issued_subkeys: 2 @@ -17,9 +17,9 @@ deterministic_key { } type: DETERMINISTIC_KEY -public_key: "\002\330b\034\023\320\217|!\271p\034\017p\330!\245\233j\376\b\316\373\231D\324\271d\217h\217\016^" +public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370" deterministic_key { - chain_code: "\367j\245\025U\265\346\v\234\275\343\rd\214q\004\232\253\312\222Hi\305\201\370`^\304\210\034p*" + chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311" path: 2147483648 path: 1 issued_subkeys: 1 @@ -27,207 +27,207 @@ deterministic_key { } type: DETERMINISTIC_KEY -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" +public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377" deterministic_key { - chain_code: "RS\20672^\r\265\fNCd\305\235\266\a\232\033\303\316\230\376FK\322\314\300}\335zk\016" + chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035" path: 2147483648 path: 0 path: 0 } type: DETERMINISTIC_KEY -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" +public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313" deterministic_key { - chain_code: ":JV\362\341\275\220\370r\031@\272\225,\307B\v\023\017\277\b\02000\261\225\026\355J\b\316G" + chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306" path: 2147483648 path: 0 path: 1 } type: DETERMINISTIC_KEY -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" +public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-" deterministic_key { - chain_code: "\005\2717\377\3625\362\017`\270\370k\301B\241C[\350\213\244m{L&C\244\250\200$\f\025\357" + chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324" path: 2147483648 path: 0 path: 2 } type: DETERMINISTIC_KEY -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" +public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215" deterministic_key { - chain_code: "$\211\377\t\276\033I!*\320\003\316\260Bl\r^ w\276\300\025\251\ak\317\342\034@9\204\374" + chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t" path: 2147483648 path: 0 path: 3 } type: DETERMINISTIC_KEY -public_key: "\003\273\222i0kH\005\313e\373\306c\021\340u\275\353\231\224i\333\357\017r\372\200\036PW\311\356," +public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m" deterministic_key { - chain_code: "f\315\357Y0\037\033\377)|\234\273\267\234\324\000\251\263#&\\\255tZ\313+\0003Hn\022" + chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P" path: 2147483648 path: 0 path: 4 } type: DETERMINISTIC_KEY -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" +public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV" deterministic_key { - chain_code: "\372\232\306\242\340P\251\037\227\222z\311\260\f\350 \2627@\223\247\333= \2118\331\344\006\236\362m" + chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215" path: 2147483648 path: 0 path: 5 } type: DETERMINISTIC_KEY -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" +public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X" deterministic_key { - chain_code: "\2714Rw\317\230\001\356h\203\216z\230xL~[lR\032\275\247\277\362r\333q\220\242`\206\275" + chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg" path: 2147483648 path: 0 path: 6 } type: DETERMINISTIC_KEY -public_key: "\002\361z\203\341\345\350\214L\272\262\301-8/\246xX\'\r\027\026#^M\a\313\277\356\354B\022" +public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355" deterministic_key { - chain_code: "\242\3452\270\275\321\363\206#\310\206\222\2359%tH\364\343\271\266\372I\204U\031Y\325CIbY" + chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313" path: 2147483648 path: 0 path: 7 } type: DETERMINISTIC_KEY -public_key: "\003l\021W\350G\026kc\225\213\307Rv1[p\270P\r\266T\275\021\b\270\335\'\270\254\307\242:" +public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b" deterministic_key { - chain_code: "\364E\240q\263\227Y\200\361q/\212X\343i\234\226\235\036+\n\036&\203(\341\002\235\270\021U\342" + chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224" path: 2147483648 path: 0 path: 8 } type: DETERMINISTIC_KEY -public_key: "\003KaP\210J\320\354\202\024#*#\323\276i\\\004\341\225\253qw_\235\371\370\316\315N\rZ\031" +public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419" deterministic_key { - chain_code: "\2561\251Rw\2434%\304\v]\020\220d\370\234<\217\214\306\363\361\033\262\204\265}#\224\333\255\031" + chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-" path: 2147483648 path: 0 path: 9 } type: DETERMINISTIC_KEY -public_key: "\003\250\371\347\214\240t\242\355\277\231\3351\227g\222\375\363[\326p9\244\032\305^}\003)\000\035\252E" +public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K" deterministic_key { - chain_code: "\362\203\2555\335\3013\037\361\200-\245i\225\024\322\274V#;\3157`$\360\206\332?/P]\034" + chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225" path: 2147483648 path: 0 path: 10 } type: DETERMINISTIC_KEY -public_key: "\002\263\220\a\311h`\216?m\375\232V\205\025zi,`\203\252{\323,&\247\304\263\006K\035j\261" +public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323" deterministic_key { - chain_code: "\251K\330\274\360\254q\267\005\3331\2716\277M\3544\352S\006\243\317\223\305Y\304\317\r#\233\362H" + chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200" path: 2147483648 path: 0 path: 11 } type: DETERMINISTIC_KEY -public_key: "\002\336\201guA0\314$\016\335\016xTY\237I\327Zx\217\365K,k\334g\211\202\3770\247X" +public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\" deterministic_key { - chain_code: "WV#4$\027\034m\023\353\235U\021,\327\303\327[\b\003\255$\024\243v\2306\276\230/\273\021" + chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330" path: 2147483648 path: 1 path: 0 } type: DETERMINISTIC_KEY -public_key: "\002\221\322\332>W&\00475\374\317jP\021\332[[\276\363\016\2636\322:\321\361\032!?q-\320" +public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;" deterministic_key { - chain_code: "\036\364!\212\223\235\037\333\346\215o\344MD4\303\206\215\327M\354.\210\201c\353\267\254\245\250\257\273" + chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313" path: 2147483648 path: 1 path: 1 } type: DETERMINISTIC_KEY -public_key: "\003\204\311|\002}\002\201IQ\003c\253\335Ay\220@3\210\001~\345L\216u\030\217\232\262m{\371" +public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000" deterministic_key { - chain_code: "\036\026\334\313\264\227\025Y\n\367X8\b\355F,\262h\2246\373\203M1\355\254>\320\r5M\r" + chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341" path: 2147483648 path: 1 path: 2 } type: DETERMINISTIC_KEY -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" +public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237" deterministic_key { - chain_code: "N_\376\r\372n\000\263\353\v\220Z\254\023\307z)M\243g\200L\305\tU\n\n\354+C\016\277" + chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#" path: 2147483648 path: 1 path: 3 } type: DETERMINISTIC_KEY -public_key: "\003\000\344v\304py\001-]ut\245\32027\265\367R\331\026o\v\372|\213b1\343\356\250#" +public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321" deterministic_key { - chain_code: "\030@\276\337|\300\303\255\262\374\001\222\023\240%\220\274\306=\242$\213\356\355URv2\210\257\350\201" + chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225" path: 2147483648 path: 1 path: 4 } type: DETERMINISTIC_KEY -public_key: "\002P\254\2652\374\234\312\250\325\300\212\367\217F\275~\370\200\270T\260\323\317\030\200\240\242" + chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266" path: 2147483648 path: 1 path: 5 } type: DETERMINISTIC_KEY -public_key: "\003\000\323\225^\225\032\275R\267\347\213\256\033-\252\302\322`%fL\326\bo\337\367c\232\241\310\354\330" +public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341" deterministic_key { - chain_code: "z\335|\370>\237\231\311ML3\360/\371\203\243#\037\3555\a%\231]4\213\310=\332\316\002\232" + chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232" path: 2147483648 path: 1 path: 6 } type: DETERMINISTIC_KEY -public_key: "\003\310\264dd\275\026\211\247\324\221\207edi\353\036\246\350\366\370\264\213\266\357_\332x}gI\367-" +public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230" deterministic_key { - chain_code: "\031\\\223*!\004\361\353|\347.\274\032P\275\337\n\224\233\230\216\2660\246\241\311\t>\255\016\313\204" + chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335" path: 2147483648 path: 1 path: 7 } type: DETERMINISTIC_KEY -public_key: "\003\226\253\321\200\001\346u\020_C9\nj\001} \212\027\341-f\f=\320~\311\200ck@\361\341" +public_key: "\003X\331\344\227G\366//\353[U" +public_key: "\003\307\273B\334\212\303\025r\212\264|\250c\204\\=\360w\335\300\353\266\273\3209\260nl3\271+" deterministic_key { - chain_code: "\306#\361\242\241\016-\346\341\330\325\331\352\231\220X\267y\207\302\020\353#\345\0033{\345\353\244\3362" + chain_code: "\345\365\034\261\316\2121R\226/+\267K\326C&\236\246],\224\001\220\347\334\351\223K\023\252\360\023" path: 2147483648 path: 1 path: 9 } type: DETERMINISTIC_KEY -public_key: "\003J\371[{Vs\232A\260\343\376!\265\a\031`\0239\277=jd\n\230\270\034\350#\302}x\334" +public_key: "\002+[\230[E\225\225R2\350X=\366\343\244\237\260\220J\311\376\200@\\\334\312y\212\276\223\350\267" deterministic_key { - chain_code: "c\330\261\301\001\215\307\v\374M\231B7!/x/\215\341\265\312\027b+%\032\304\322z\304`\254" + chain_code: "\250W]}O:@\t\016\311\016\335\016\271\260\327\261\237\030G\334\246\233\352t\266\\S\311\333m*" path: 2147483648 path: 1 path: 10 diff --git a/core/src/wallet.proto b/core/src/wallet.proto index 3d2b36685..e74a9e5ed 100644 --- a/core/src/wallet.proto +++ b/core/src/wallet.proto @@ -86,10 +86,10 @@ message Key { ENCRYPTED_SCRYPT_AES = 2; /** - * Not really a key, but rather contains the seed for a deterministic key hierarchy in the private_key field. - * The label and public_key fields are missing. Creation timestamp will exist. - */ - DETERMINISTIC_ROOT_SEED = 3; + * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field. + * The label and public_key fields are missing. Creation timestamp will exist. + */ + DETERMINISTIC_MNEMONIC = 3; /** * A key that was derived deterministically. Note that the root seed that created it may NOT be present in the @@ -99,13 +99,6 @@ message Key { * key can be rederived on the fly. */ DETERMINISTIC_KEY = 4; - - /** - * Not really a key, but rather contains the mnemonic phrase for a deterministic key hierarchy in the private_key field. - * The label and public_key fields are missing. Creation timestamp will exist. - * Must be immediately after DETERMINISTIC_KEY - */ - DETERMINISTIC_MNEMONIC = 5; } required Type type = 1; @@ -116,7 +109,7 @@ message Key { optional EncryptedData encrypted_data = 6; // The public EC key derived from the private key. We allow both to be stored to avoid mobile clients having to - // do lots of slow EC math on startup. For DETERMINISTIC_ROOT_SEED and DETERMINISTIC_MNEMONIC entries this is missing. + // do lots of slow EC math on startup. For DETERMINISTIC_MNEMONIC entries this is missing. optional bytes public_key = 3; // User-provided label associated with the key.