Remove support for mnemonic-less keychains

This commit is contained in:
Devrandom 2014-07-08 14:02:30 -07:00 committed by Mike Hearn
parent 2fae12064c
commit fec6cbc7df
9 changed files with 276 additions and 358 deletions

View file

@ -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<Protos.Key> 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<ECKey, Protos.Key.Builder> keys = basicKeyChain.serializeToEditableProtobufs();
for (Map.Entry<ECKey, Protos.Key.Builder> 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()))

View file

@ -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<String> mnemonicCode;
@Nullable private EncryptedData encryptedMnemonicCode;
private final long creationTimeSeconds;
@ -69,33 +67,24 @@ public class DeterministicSeed implements EncryptableItem {
}
}
DeterministicSeed(byte[] unencryptedSeed, List<String> 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<String> 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<String> 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<String> 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<String> decodeMnemonicCode(byte[] mnemonicCode) throws UnreadableWalletException {
private static List<String> 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<String> decodeMnemonicCode(String mnemonicCode) {
return Splitter.on(" ").splitToList(mnemonicCode);
}
}

View file

@ -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);
}

View file

@ -2526,15 +2526,15 @@ public final class Protos {
*/
ENCRYPTED_SCRYPT_AES(1, 2),
/**
* <code>DETERMINISTIC_ROOT_SEED = 3;</code>
* <code>DETERMINISTIC_MNEMONIC = 3;</code>
*
* <pre>
**
* 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.
* </pre>
*/
DETERMINISTIC_ROOT_SEED(2, 3),
DETERMINISTIC_MNEMONIC(2, 3),
/**
* <code>DETERMINISTIC_KEY = 4;</code>
*
@ -2548,17 +2548,6 @@ public final class Protos {
* </pre>
*/
DETERMINISTIC_KEY(3, 4),
/**
* <code>DETERMINISTIC_MNEMONIC = 5;</code>
*
* <pre>
**
* 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
* </pre>
*/
DETERMINISTIC_MNEMONIC(4, 5),
;
/**
@ -2578,15 +2567,15 @@ public final class Protos {
*/
public static final int ENCRYPTED_SCRYPT_AES_VALUE = 2;
/**
* <code>DETERMINISTIC_ROOT_SEED = 3;</code>
* <code>DETERMINISTIC_MNEMONIC = 3;</code>
*
* <pre>
**
* 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.
* </pre>
*/
public static final int DETERMINISTIC_ROOT_SEED_VALUE = 3;
public static final int DETERMINISTIC_MNEMONIC_VALUE = 3;
/**
* <code>DETERMINISTIC_KEY = 4;</code>
*
@ -2600,17 +2589,6 @@ public final class Protos {
* </pre>
*/
public static final int DETERMINISTIC_KEY_VALUE = 4;
/**
* <code>DETERMINISTIC_MNEMONIC = 5;</code>
*
* <pre>
**
* 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
* </pre>
*/
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() {

View file

@ -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<List<ECKey>> 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<ECKey> 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);

View file

@ -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<Protos.Key> 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<Protos.Key> 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);
}
}

View file

@ -1,28 +1,28 @@
type: DETERMINISTIC_ROOT_SEED
secret_bytes: "\004<r\377aT\'\356M\257w\260R\006\253\322}\343\267eW6S\233\210\352NS;\275I-"
type: DETERMINISTIC_MNEMONIC
secret_bytes: "aerobic toe save section draw warm cute upon raccoon mother priority pilot taste sweet next traffic fatal sword dentist original crisp team caution rebel"
creation_timestamp: 1389353062000
type: DETERMINISTIC_KEY
secret_bytes: "\241\346\003RF\t\027\367\a\f\333^C&\302-\335\314\353t&h\335{ \032\364\267\335\235\345\276"
public_key: "\003\361\245l\225\304\247X]\256,_hn\362\031\243\220\220\237z0\\<\022-O\ts\244\250\344A"
secret_bytes: "\270E0\202(\362b\023\276\264\347\226E2\360\221\347\325\233L\203\3276\272\213\2436&\304\373\221\025"
public_key: "\002\342$\253\332\031\352\324q\316M\251}\274\267\370X$\366>Q\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: "<M\020I\364\276\336Z\255\341\330\257\337 \366E_\027\2433w\325\263\"$\350\f\244\006\251u\021"
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
@ -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<h\b/&\223\022\343<*\266\317\372\305\373\320J\246\324\321\357y\2736"
public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t"
deterministic_key {
chain_code: "\327\343\333W\312\005\321\a\271`\354\265>\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//<V\226\b\352#\315\307j\263\232\273d\236)\004\225fk\304\000XM\305"
deterministic_key {
chain_code: "\253\201\367\346\275\232\320\314\276\005\373\031\316\355\270\276(D\220\364\343\310\370\347\272\2759\232s\300\2218"
chain_code: "&\025?\264\a\2334-\203\217\240R\221[{8)9\221\346bv=ut\346\226KVj\2659"
path: 2147483648
path: 1
path: 8
}
type: DETERMINISTIC_KEY
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"
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

View file

@ -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<h\b/&\223\022\343<*\266\317\372\305\373\320J\246\324\321\357y\2736"
public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t"
deterministic_key {
chain_code: "\327\343\333W\312\005\321\a\271`\354\265>\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//<V\226\b\352#\315\307j\263\232\273d\236)\004\225fk\304\000XM\305"
deterministic_key {
chain_code: "\253\201\367\346\275\232\320\314\276\005\373\031\316\355\270\276(D\220\364\343\310\370\347\272\2759\232s\300\2218"
chain_code: "&\025?\264\a\2334-\203\217\240R\221[{8)9\221\346bv=ut\346\226KVj\2659"
path: 2147483648
path: 1
path: 8
}
type: DETERMINISTIC_KEY
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"
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

View file

@ -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.