Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ public static List<DeterministicKeyChain> fromProtobuf(List<Protos.Key> keys, @N
if (key.hasDeterministicSeed()) {
seedBytes = key.getDeterministicSeed().toByteArray();
}
seed = new DeterministicSeed(key.getSecretBytes().toStringUtf8(), seedBytes, passphrase, seedCreationTime);
seed = DeterministicSeed.fromProtobuf(key.getSecretBytes().toStringUtf8(), seedBytes, passphrase, seedCreationTime);
} else if (key.hasEncryptedData()) {
if (key.hasDeterministicSeed())
throw new UnreadableWalletException("Malformed key proto: " + key);
Expand All @@ -892,7 +892,7 @@ public static List<DeterministicKeyChain> fromProtobuf(List<Protos.Key> keys, @N
encryptedSeedBytes = new EncryptedData(encryptedSeed.getInitialisationVector().toByteArray(),
encryptedSeed.getEncryptedPrivateKey().toByteArray());
}
seed = new DeterministicSeed(data, encryptedSeedBytes, seedCreationTime);
seed = DeterministicSeed.fromProtobufEncrypted(data, encryptedSeedBytes, seedCreationTime);
} else {
throw new UnreadableWalletException("Malformed key proto: " + key);
}
Expand Down
72 changes: 36 additions & 36 deletions core/src/main/java/org/bitcoinj/wallet/DeterministicSeed.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class DeterministicSeed implements EncryptableItem {
* @param creationTime when the seed was originally created
*/
public static DeterministicSeed ofMnemonic(String mnemonicCode, String passphrase, Instant creationTime) {
return new DeterministicSeed(mnemonicCode, null, passphrase, Objects.requireNonNull(creationTime));
return new DeterministicSeed(seedFromMnemonic(splitMnemonicCode(mnemonicCode), passphrase), splitMnemonicCode(mnemonicCode), Objects.requireNonNull(creationTime));
}

/**
Expand All @@ -76,7 +76,7 @@ public static DeterministicSeed ofMnemonic(String mnemonicCode, String passphras
* @param passphrase user supplied passphrase, or empty string if there is no passphrase
*/
public static DeterministicSeed ofMnemonic(String mnemonicCode, String passphrase) {
return new DeterministicSeed(mnemonicCode, null, passphrase, null);
return new DeterministicSeed(seedFromMnemonic(splitMnemonicCode(mnemonicCode), passphrase), splitMnemonicCode(mnemonicCode), null);
}

/**
Expand All @@ -87,7 +87,7 @@ public static DeterministicSeed ofMnemonic(String mnemonicCode, String passphras
* @param creationTime when the seed was originally created
*/
public static DeterministicSeed ofMnemonic(List<String> mnemonicCode, String passphrase, Instant creationTime) {
return new DeterministicSeed(mnemonicCode, null, passphrase, Objects.requireNonNull(creationTime));
return new DeterministicSeed(seedFromMnemonic(mnemonicCode, passphrase), mnemonicCode, Objects.requireNonNull(creationTime));
}

/**
Expand All @@ -97,7 +97,7 @@ public static DeterministicSeed ofMnemonic(List<String> mnemonicCode, String pas
* @param passphrase user supplied passphrase, or empty string if there is no passphrase
*/
public static DeterministicSeed ofMnemonic(List<String> mnemonicCode, String passphrase) {
return new DeterministicSeed(mnemonicCode, null, passphrase, null);
return new DeterministicSeed(seedFromMnemonic(mnemonicCode, passphrase), mnemonicCode, null);
}

/**
Expand All @@ -108,7 +108,7 @@ public static DeterministicSeed ofMnemonic(List<String> mnemonicCode, String pas
* @param creationTime when the seed was originally created
*/
public static DeterministicSeed ofEntropy(byte[] entropy, String passphrase, Instant creationTime) {
return new DeterministicSeed(entropy, passphrase, Objects.requireNonNull(creationTime));
return DeterministicSeed.ofEntropyInternal(entropy, passphrase, Objects.requireNonNull(creationTime));
}

/**
Expand All @@ -118,7 +118,15 @@ public static DeterministicSeed ofEntropy(byte[] entropy, String passphrase, Ins
* @param passphrase user supplied passphrase, or empty string if there is no passphrase
*/
public static DeterministicSeed ofEntropy(byte[] entropy, String passphrase) {
return new DeterministicSeed(entropy, passphrase, null);
return DeterministicSeed.ofEntropyInternal(entropy, passphrase, null);
}

private static DeterministicSeed ofEntropyInternal(byte[] entropy, String passphrase, @Nullable Instant creationTime) {
checkArgument(entropy.length * 8 >= DEFAULT_SEED_ENTROPY_BITS, () -> "entropy size too small");
Objects.requireNonNull(passphrase);
List<String> mnemonicCode = MnemonicCode.INSTANCE.toMnemonic(entropy);
byte[] seed = MnemonicCode.toSeed(mnemonicCode, passphrase);
return new DeterministicSeed(seed, mnemonicCode, creationTime);
}

/**
Expand All @@ -129,18 +137,20 @@ public static DeterministicSeed ofEntropy(byte[] entropy, String passphrase) {
* @param passphrase user supplied passphrase, or empty string if there is no passphrase
*/
public static DeterministicSeed ofRandom(SecureRandom random, int bits, String passphrase) {
return new DeterministicSeed(random, bits, passphrase);
return DeterministicSeed.ofEntropyInternal(getEntropy(random, bits), Objects.requireNonNull(passphrase), TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS));
}

/**
* Internal use only – will be restricted to private in a future release.
* Use {@link #ofMnemonic(String, String, Instant)} or {@link #ofMnemonic(String, String)} instead.
*/
DeterministicSeed(String mnemonicString, byte[] seed, String passphrase, @Nullable Instant creationTime) {
this(decodeMnemonicCode(mnemonicString), seed, passphrase, creationTime);
// For use in DeteministicKeyChain.fromProtobuf() only
static DeterministicSeed fromProtobuf(String mnemonicString, byte @Nullable [] seed, String passphrase, @Nullable Instant creationTime) {
return new DeterministicSeed(optionalSeedFromMnemonic(splitMnemonicCode(mnemonicString), passphrase, seed), splitMnemonicCode(mnemonicString), creationTime);
}

// For use in DeteministicKeyChain.fromProtobuf() only
static DeterministicSeed fromProtobufEncrypted(EncryptedData encryptedMnemonic, @Nullable EncryptedData encryptedSeed, @Nullable Instant creationTime) {
return new DeterministicSeed(encryptedMnemonic, encryptedSeed, creationTime);
}

/** Internal use only. */
// Canonical constructor: both seed and mnemonic sentence are present
private DeterministicSeed(byte[] seed, List<String> mnemonic, @Nullable Instant creationTime) {
this.seed = Objects.requireNonNull(seed);
this.mnemonicCode = Objects.requireNonNull(mnemonic);
Expand All @@ -149,34 +159,22 @@ private DeterministicSeed(byte[] seed, List<String> mnemonic, @Nullable Instant
this.creationTime = creationTime;
}

/** Internal use only – will be restricted to private in a future release. */
DeterministicSeed(EncryptedData encryptedMnemonic, @Nullable EncryptedData encryptedSeed, @Nullable Instant creationTime) {
// Canonical constructor: encrypted mnemonic sentence and optional encrypted seed
private DeterministicSeed(EncryptedData encryptedMnemonic, @Nullable EncryptedData encryptedSeed, @Nullable Instant creationTime) {
this.seed = null;
this.mnemonicCode = null;
this.encryptedMnemonicCode = Objects.requireNonNull(encryptedMnemonic);
this.encryptedSeed = encryptedSeed;
this.creationTime = creationTime;
}

/** Internal use only. */
private DeterministicSeed(List<String> mnemonicCode, byte @Nullable [] seed, String passphrase, @Nullable Instant creationTime) {
this((seed != null ? seed : MnemonicCode.toSeed(mnemonicCode, Objects.requireNonNull(passphrase))), mnemonicCode, creationTime);
// If seed is null, generate seed from mnemonic and passphrase. Otherwise, return unmodified seed.
private static byte[] optionalSeedFromMnemonic(List<String> mnemonicCode, String passphrase, byte @Nullable [] seed) {
return seed != null ? seed : seedFromMnemonic(mnemonicCode, passphrase);
}

private DeterministicSeed(SecureRandom random, int bits, String passphrase) {
this(getEntropy(random, bits), Objects.requireNonNull(passphrase), TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS));
}

/** Internal use only. */
private DeterministicSeed(byte[] entropy, String passphrase, @Nullable Instant creationTime) {
checkArgument(entropy.length * 8 >= DEFAULT_SEED_ENTROPY_BITS, () -> "entropy size too small");
Objects.requireNonNull(passphrase);

this.mnemonicCode = MnemonicCode.INSTANCE.toMnemonic(entropy);
this.seed = MnemonicCode.toSeed(mnemonicCode, passphrase);
this.encryptedMnemonicCode = null;
this.encryptedSeed = null;
this.creationTime = creationTime;
private static byte[] seedFromMnemonic(List<String> mnemonicCode, String passphrase) {
return MnemonicCode.toSeed(mnemonicCode, Objects.requireNonNull(passphrase));
}

private static byte[] getEntropy(SecureRandom random, int bits) {
Expand Down Expand Up @@ -281,7 +279,7 @@ public DeterministicSeed decrypt(KeyCrypter crypter, String passphrase, AesKey a
Objects.requireNonNull(encryptedMnemonicCode);
List<String> mnemonic = decodeMnemonicCode(crypter.decrypt(encryptedMnemonicCode, aesKey));
byte[] seed = encryptedSeed == null ? null : crypter.decrypt(encryptedSeed, aesKey);
return new DeterministicSeed(mnemonic, seed, passphrase, creationTime);
return new DeterministicSeed(optionalSeedFromMnemonic(mnemonic, passphrase, seed), mnemonic, creationTime);
}

@Override
Expand Down Expand Up @@ -326,11 +324,13 @@ public String getMnemonicString() {
return mnemonicCode != null ? InternalUtils.SPACE_JOINER.join(mnemonicCode) : null;
}

// decode to String from byte[]
private static List<String> decodeMnemonicCode(byte[] mnemonicCode) {
return decodeMnemonicCode(new String(mnemonicCode, StandardCharsets.UTF_8));
return splitMnemonicCode(new String(mnemonicCode, StandardCharsets.UTF_8));
}

private static List<String> decodeMnemonicCode(String mnemonicCode) {
// Split mnemonic code into List<String>
private static List<String> splitMnemonicCode(String mnemonicCode) {
return InternalUtils.WHITESPACE_SPLITTER.splitToList(mnemonicCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ private String readResourceFile(String filename) {

@Test
public void testToString() {
DeterministicSeed seed = new DeterministicSeed("correct horse battery staple", null, "", Instant.ofEpochSecond(1000L));
DeterministicSeed seed = DeterministicSeed.ofMnemonic("correct horse battery staple", "", Instant.ofEpochSecond(1000L));
DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed).build();

String str = chain.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class DeterministicSeedTest {
@Test
public void testToString() {
long creationTime = 1000L;
DeterministicSeed seed = new DeterministicSeed("correct horse battery staple", null, "", Instant.ofEpochSecond(creationTime));
DeterministicSeed seed = DeterministicSeed.ofMnemonic("correct horse battery staple", "", Instant.ofEpochSecond(creationTime));

String s1 = seed.toString();
assertTrue(s1.contains("DeterministicSeed"));
Expand Down
Loading