正在查看: imToken v3.28.8 应用的 DeterministicKeyChain.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: imToken v3.28.8 应用的 DeterministicKeyChain.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package org.bitcoinj.wallet;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.UnmodifiableIterator;
import com.google.protobuf.ByteString;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import org.bitcoinj.core.BloomFilter;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Utils;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicHierarchy;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.EncryptedData;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.crypto.KeyCrypter;
import org.bitcoinj.crypto.KeyCrypterException;
import org.bitcoinj.crypto.KeyCrypterScrypt;
import org.bitcoinj.script.Script;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.KeyChain;
import org.bitcoinj.wallet.Protos;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.crypto.params.KeyParameter;
public class DeterministicKeyChain implements EncryptableKeyChain {
public static final String DEFAULT_PASSPHRASE_FOR_MNEMONIC = "";
private static final int LAZY_CALCULATE_LOOKAHEAD = -1;
private final BasicKeyChain basicKeyChain;
private DeterministicKey externalParentKey;
private DeterministicHierarchy hierarchy;
private DeterministicKey internalParentKey;
private boolean isFollowing;
private int issuedExternalKeys;
private int issuedInternalKeys;
private int keyLookaheadEpoch;
protected final ReentrantLock lock;
protected int lookaheadSize;
protected int lookaheadThreshold;
@Nullable
private DeterministicKey rootKey;
@Nullable
private DeterministicSeed seed;
protected int sigsRequiredToSpend;
private static final Logger log = LoggerFactory.getLogger(DeterministicKeyChain.class);
public static final ImmutableList<ChildNumber> ACCOUNT_ZERO_PATH = ImmutableList.of(ChildNumber.ZERO_HARDENED);
public static final ImmutableList<ChildNumber> EXTERNAL_SUBPATH = ImmutableList.of(ChildNumber.ZERO);
public static final ImmutableList<ChildNumber> INTERNAL_SUBPATH = ImmutableList.of(ChildNumber.ONE);
public static final ImmutableList<ChildNumber> EXTERNAL_PATH = HDUtils.concat(ACCOUNT_ZERO_PATH, EXTERNAL_SUBPATH);
public static final ImmutableList<ChildNumber> INTERNAL_PATH = HDUtils.concat(ACCOUNT_ZERO_PATH, INTERNAL_SUBPATH);
public static final ImmutableList<ChildNumber> BIP44_ACCOUNT_ZERO_PATH = ImmutableList.of(new ChildNumber(44, true), ChildNumber.ZERO_HARDENED, ChildNumber.ZERO_HARDENED);
@Nullable
public RedeemData findRedeemDataByScriptHash(ByteString byteString) {
return null;
}
public boolean isMarried() {
return false;
}
public void maybeLookAheadScripts() {
}
private int calcDefaultLookaheadThreshold() {
return this.lookaheadSize / 3;
}
public static class Builder<T extends Builder<T>> {
protected int bits = 128;
protected byte[] entropy;
protected String passphrase;
protected SecureRandom random;
protected DeterministicSeed seed;
protected long seedCreationTimeSecs;
protected DeterministicKey watchingKey;
protected T self() {
return this;
}
protected Builder() {
}
public T entropy(byte[] bArr) {
this.entropy = bArr;
return self();
}
public T seed(DeterministicSeed deterministicSeed) {
this.seed = deterministicSeed;
return self();
}
public T random(SecureRandom secureRandom, int i) {
this.random = secureRandom;
this.bits = i;
return self();
}
public T random(SecureRandom secureRandom) {
this.random = secureRandom;
return self();
}
public T watchingKey(DeterministicKey deterministicKey) {
this.watchingKey = deterministicKey;
return self();
}
public T seedCreationTimeSecs(long j) {
this.seedCreationTimeSecs = j;
return self();
}
public T passphrase(String str) {
this.passphrase = str;
return self();
}
public DeterministicKeyChain build() {
Preconditions.checkState((this.random == null && this.entropy == null && this.seed == null && this.watchingKey == null) ? false : true, "Must provide either entropy or random or seed or watchingKey");
Preconditions.checkState(this.passphrase == null || this.seed == null, "Passphrase must not be specified with seed");
SecureRandom secureRandom = this.random;
if (secureRandom != null) {
return new DeterministicKeyChain(secureRandom, this.bits, getPassphrase(), this.seedCreationTimeSecs);
}
byte[] bArr = this.entropy;
if (bArr != null) {
return new DeterministicKeyChain(bArr, getPassphrase(), this.seedCreationTimeSecs);
}
DeterministicSeed deterministicSeed = this.seed;
if (deterministicSeed != null) {
deterministicSeed.setCreationTimeSeconds(this.seedCreationTimeSecs);
return new DeterministicKeyChain(this.seed);
}
this.watchingKey.setCreationTimeSeconds(this.seedCreationTimeSecs);
return new DeterministicKeyChain(this.watchingKey);
}
protected String getPassphrase() {
String str = this.passphrase;
return str != null ? str : "";
}
}
public static Builder<?> builder() {
return new Builder<>();
}
public DeterministicKeyChain(SecureRandom secureRandom) {
this(secureRandom, 128, "", Utils.currentTimeSeconds());
}
public DeterministicKeyChain(SecureRandom secureRandom, int i) {
this(secureRandom, i, "", Utils.currentTimeSeconds());
}
public DeterministicKeyChain(SecureRandom secureRandom, int i, String str, long j) {
this(new DeterministicSeed(secureRandom, i, str, j));
}
public DeterministicKeyChain(byte[] bArr, String str, long j) {
this(new DeterministicSeed(bArr, str, j));
}
protected DeterministicKeyChain(DeterministicSeed deterministicSeed) {
this(deterministicSeed, (KeyCrypter) null);
}
public DeterministicKeyChain(DeterministicKey deterministicKey) {
this.lock = Threading.lock("DeterministicKeyChain");
this.lookaheadSize = 100;
this.lookaheadThreshold = calcDefaultLookaheadThreshold();
this.sigsRequiredToSpend = 1;
Preconditions.checkArgument(deterministicKey.isPubKeyOnly(), "Private subtrees not currently supported: if you got this key from DKC.getWatchingKey() then use .dropPrivate().dropParent() on it first.");
Preconditions.checkArgument(deterministicKey.getPath().size() == getAccountPath().size(), "You can only watch an account key currently");
this.basicKeyChain = new BasicKeyChain();
this.seed = null;
this.rootKey = null;
addToBasicChain(deterministicKey);
this.hierarchy = new DeterministicHierarchy(deterministicKey);
initializeHierarchyUnencrypted(deterministicKey);
}
protected DeterministicKeyChain(DeterministicKey deterministicKey, boolean z) {
this(deterministicKey);
this.isFollowing = z;
}
public static DeterministicKeyChain watchAndFollow(DeterministicKey deterministicKey) {
return new DeterministicKeyChain(deterministicKey, true);
}
public static DeterministicKeyChain watch(DeterministicKey deterministicKey) {
return new DeterministicKeyChain(deterministicKey);
}
protected DeterministicKeyChain(DeterministicSeed deterministicSeed, @Nullable KeyCrypter keyCrypter) {
this.lock = Threading.lock("DeterministicKeyChain");
this.lookaheadSize = 100;
this.lookaheadThreshold = calcDefaultLookaheadThreshold();
this.sigsRequiredToSpend = 1;
this.seed = deterministicSeed;
this.basicKeyChain = new BasicKeyChain(keyCrypter);
if (deterministicSeed.isEncrypted()) {
return;
}
DeterministicKey createMasterPrivateKey = HDKeyDerivation.createMasterPrivateKey((byte[]) Preconditions.checkNotNull(deterministicSeed.getSeedBytes()));
this.rootKey = createMasterPrivateKey;
createMasterPrivateKey.setCreationTimeSeconds(deterministicSeed.getCreationTimeSeconds());
addToBasicChain(this.rootKey);
this.hierarchy = new DeterministicHierarchy(this.rootKey);
for (int i = 1; i <= getAccountPath().size(); i++) {
addToBasicChain(this.hierarchy.get(getAccountPath().subList(0, i), false, true));
}
initializeHierarchyUnencrypted(this.rootKey);
}
protected DeterministicKeyChain(KeyCrypter keyCrypter, KeyParameter keyParameter, DeterministicKeyChain deterministicKeyChain) {
this.lock = Threading.lock("DeterministicKeyChain");
this.lookaheadSize = 100;
this.lookaheadThreshold = calcDefaultLookaheadThreshold();
this.sigsRequiredToSpend = 1;
Preconditions.checkNotNull(deterministicKeyChain.rootKey);
Preconditions.checkNotNull(deterministicKeyChain.seed);
Preconditions.checkArgument(!deterministicKeyChain.rootKey.isEncrypted(), "Chain already encrypted");
this.issuedExternalKeys = deterministicKeyChain.issuedExternalKeys;
this.issuedInternalKeys = deterministicKeyChain.issuedInternalKeys;
this.lookaheadSize = deterministicKeyChain.lookaheadSize;
this.lookaheadThreshold = deterministicKeyChain.lookaheadThreshold;
this.seed = deterministicKeyChain.seed.encrypt(keyCrypter, keyParameter);
this.basicKeyChain = new BasicKeyChain(keyCrypter);
DeterministicKey encrypt = deterministicKeyChain.rootKey.encrypt(keyCrypter, keyParameter, null);
this.rootKey = encrypt;
this.hierarchy = new DeterministicHierarchy(encrypt);
this.basicKeyChain.importKey(this.rootKey);
for (int i = 1; i < getAccountPath().size(); i++) {
encryptNonLeaf(keyParameter, deterministicKeyChain, this.rootKey, getAccountPath().subList(0, i));
}
DeterministicKey encryptNonLeaf = encryptNonLeaf(keyParameter, deterministicKeyChain, this.rootKey, getAccountPath());
this.externalParentKey = encryptNonLeaf(keyParameter, deterministicKeyChain, encryptNonLeaf, HDUtils.concat(getAccountPath(), EXTERNAL_SUBPATH));
this.internalParentKey = encryptNonLeaf(keyParameter, deterministicKeyChain, encryptNonLeaf, HDUtils.concat(getAccountPath(), INTERNAL_SUBPATH));
Iterator<ECKey> it = deterministicKeyChain.basicKeyChain.getKeys().iterator();
while (it.hasNext()) {
DeterministicKey deterministicKey = (DeterministicKey) it.next();
if (deterministicKey.getPath().size() == getAccountPath().size() + 2) {
DeterministicKey deterministicKey2 = new DeterministicKey(deterministicKey.dropPrivateBytes(), this.hierarchy.get(((DeterministicKey) Preconditions.checkNotNull(deterministicKey.getParent())).getPath(), false, false));
this.hierarchy.putKey(deterministicKey2);
this.basicKeyChain.importKey(deterministicKey2);
}
}
}
protected ImmutableList<ChildNumber> getAccountPath() {
return ACCOUNT_ZERO_PATH;
}
private DeterministicKey encryptNonLeaf(KeyParameter keyParameter, DeterministicKeyChain deterministicKeyChain, DeterministicKey deterministicKey, ImmutableList<ChildNumber> immutableList) {
DeterministicKey encrypt = deterministicKeyChain.hierarchy.get(immutableList, false, false).encrypt((KeyCrypter) Preconditions.checkNotNull(this.basicKeyChain.getKeyCrypter()), keyParameter, deterministicKey);
this.hierarchy.putKey(encrypt);
this.basicKeyChain.importKey(encrypt);
return encrypt;
}
private void initializeHierarchyUnencrypted(DeterministicKey deterministicKey) {
this.externalParentKey = this.hierarchy.deriveChild(getAccountPath(), false, false, ChildNumber.ZERO);
this.internalParentKey = this.hierarchy.deriveChild(getAccountPath(), false, false, ChildNumber.ONE);
addToBasicChain(this.externalParentKey);
addToBasicChain(this.internalParentKey);
}
@Override
public DeterministicKey getKey(KeyChain.KeyPurpose keyPurpose) {
return getKeys(keyPurpose, 1).get(0);
}
@Override
public List<DeterministicKey> getKeys(KeyChain.KeyPurpose keyPurpose, int i) {
int i2;
DeterministicKey deterministicKey;
Preconditions.checkArgument(i > 0);
this.lock.lock();
try {
int i3 = AnonymousClass1.$SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose[keyPurpose.ordinal()];
if (i3 == 1 || i3 == 2) {
i2 = this.issuedExternalKeys + i;
this.issuedExternalKeys = i2;
deterministicKey = this.externalParentKey;
} else {
if (i3 != 3 && i3 != 4) {
throw new UnsupportedOperationException();
}
i2 = this.issuedInternalKeys + i;
this.issuedInternalKeys = i2;
deterministicKey = this.internalParentKey;
}
this.basicKeyChain.importKeys(maybeLookAhead(deterministicKey, i2, 0, 0));
ArrayList arrayList = new ArrayList(i);
for (int i4 = 0; i4 < i; i4++) {
DeterministicKey deterministicKey2 = this.hierarchy.get(HDUtils.append(deterministicKey.getPath(), new ChildNumber((i2 - i) + i4, false)), false, false);
checkForBitFlip(deterministicKey2);
arrayList.add(deterministicKey2);
}
return arrayList;
} finally {
this.lock.unlock();
}
}
static class AnonymousClass1 {
static final int[] $SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose;
static {
int[] iArr = new int[KeyChain.KeyPurpose.values().length];
$SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose = iArr;
try {
iArr[KeyChain.KeyPurpose.RECEIVE_FUNDS.ordinal()] = 1;
} catch (NoSuchFieldError unused) {
}
try {
$SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose[KeyChain.KeyPurpose.REFUND.ordinal()] = 2;
} catch (NoSuchFieldError unused2) {
}
try {
$SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose[KeyChain.KeyPurpose.AUTHENTICATION.ordinal()] = 3;
} catch (NoSuchFieldError unused3) {
}
try {
$SwitchMap$org$bitcoinj$wallet$KeyChain$KeyPurpose[KeyChain.KeyPurpose.CHANGE.ordinal()] = 4;
} catch (NoSuchFieldError unused4) {
}
}
}
private void checkForBitFlip(DeterministicKey deterministicKey) {
byte[] bArr = HDKeyDerivation.deriveChildKeyBytesFromPublic((DeterministicKey) Preconditions.checkNotNull(deterministicKey.getParent()), deterministicKey.getChildNumber(), HDKeyDerivation.PublicDeriveMode.WITH_INVERSION).keyBytes;
byte[] pubKey = deterministicKey.getPubKey();
if (!Arrays.equals(bArr, pubKey)) {
throw new IllegalStateException(String.format(Locale.US, "Bit-flip check failed: %s vs %s", Arrays.toString(bArr), Arrays.toString(pubKey)));
}
}
private void addToBasicChain(DeterministicKey deterministicKey) {
this.basicKeyChain.importKeys((List<? extends ECKey>) ImmutableList.of(deterministicKey));
}
public DeterministicKey markKeyAsUsed(DeterministicKey deterministicKey) {
int i = deterministicKey.getChildNumber().i() + 1;
if (deterministicKey.getParent() == this.internalParentKey) {
if (this.issuedInternalKeys < i) {
this.issuedInternalKeys = i;
maybeLookAhead();
}
} else if (deterministicKey.getParent() == this.externalParentKey && this.issuedExternalKeys < i) {
this.issuedExternalKeys = i;
maybeLookAhead();
}
return deterministicKey;
}
public DeterministicKey findKeyFromPubHash(byte[] bArr) {
this.lock.lock();
try {
return (DeterministicKey) this.basicKeyChain.findKeyFromPubHash(bArr);
} finally {
this.lock.unlock();
}
}
public DeterministicKey findKeyFromPubKey(byte[] bArr) {
this.lock.lock();
try {
return (DeterministicKey) this.basicKeyChain.findKeyFromPubKey(bArr);
} finally {
this.lock.unlock();
}
}
@Nullable
public DeterministicKey markPubHashAsUsed(byte[] bArr) {
this.lock.lock();
try {
DeterministicKey deterministicKey = (DeterministicKey) this.basicKeyChain.findKeyFromPubHash(bArr);
if (deterministicKey != null) {
markKeyAsUsed(deterministicKey);
}
return deterministicKey;
} finally {
this.lock.unlock();
}
}
@Nullable
public DeterministicKey markPubKeyAsUsed(byte[] bArr) {
this.lock.lock();
try {
DeterministicKey deterministicKey = (DeterministicKey) this.basicKeyChain.findKeyFromPubKey(bArr);
if (deterministicKey != null) {
markKeyAsUsed(deterministicKey);
}
return deterministicKey;
} finally {
this.lock.unlock();
}
}
@Override
public boolean hasKey(ECKey eCKey) {
this.lock.lock();
try {
return this.basicKeyChain.hasKey(eCKey);
} finally {
this.lock.unlock();
}
}
protected DeterministicKey getKeyByPath(ChildNumber... childNumberArr) {
return getKeyByPath((List<ChildNumber>) ImmutableList.copyOf(childNumberArr));
}
protected DeterministicKey getKeyByPath(List<ChildNumber> list) {
return getKeyByPath(list, false);
}
public DeterministicKey getKeyByPath(List<ChildNumber> list, boolean z) {
return this.hierarchy.get(list, false, z);
}
public DeterministicKey getWatchingKey() {
return getKeyByPath((List<ChildNumber>) getAccountPath());
}
public boolean isWatching() {
return getWatchingKey().isWatching();
}
@Override
public int numKeys() {
this.lock.lock();
try {
maybeLookAhead();
return this.basicKeyChain.numKeys();
} finally {
this.lock.unlock();
}
}
public int numLeafKeysIssued() {
this.lock.lock();
try {
return this.issuedExternalKeys + this.issuedInternalKeys;
} finally {
this.lock.unlock();
}
}
@Override
public long getEarliestKeyCreationTime() {
DeterministicSeed deterministicSeed = this.seed;
if (deterministicSeed != null) {
return deterministicSeed.getCreationTimeSeconds();
}
return getWatchingKey().getCreationTimeSeconds();
}
@Override
public void addEventListener(KeyChainEventListener keyChainEventListener) {
this.basicKeyChain.addEventListener(keyChainEventListener);
}
@Override
public void addEventListener(KeyChainEventListener keyChainEventListener, Executor executor) {
this.basicKeyChain.addEventListener(keyChainEventListener, executor);
}
@Override
public boolean removeEventListener(KeyChainEventListener keyChainEventListener) {
return this.basicKeyChain.removeEventListener(keyChainEventListener);
}
@Nullable
public List<String> getMnemonicCode() {
if (this.seed == null) {
return null;
}
this.lock.lock();
try {
return this.seed.getMnemonicCode();
} finally {
this.lock.unlock();
}
}
public boolean isFollowing() {
return this.isFollowing;
}
@Override
public List<Protos.Key> serializeToProtobuf() {
ArrayList newArrayList = Lists.newArrayList();
this.lock.lock();
try {
newArrayList.addAll(serializeMyselfToProtobuf());
return newArrayList;
} finally {
this.lock.unlock();
}
}
protected List<Protos.Key> serializeMyselfToProtobuf() {
LinkedList newLinkedList = Lists.newLinkedList();
DeterministicSeed deterministicSeed = this.seed;
if (deterministicSeed != null) {
Protos.Key.Builder serializeEncryptableItem = BasicKeyChain.serializeEncryptableItem(deterministicSeed);
serializeEncryptableItem.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC);
serializeSeedEncryptableItem(this.seed, serializeEncryptableItem);
newLinkedList.add(serializeEncryptableItem.m2291build());
}
for (Map.Entry<ECKey, Protos.Key.Builder> entry : this.basicKeyChain.serializeToEditableProtobufs().entrySet()) {
DeterministicKey deterministicKey = (DeterministicKey) entry.getKey();
Protos.Key.Builder value = entry.getValue();
value.setType(Protos.Key.Type.DETERMINISTIC_KEY);
Protos.DeterministicKey.Builder deterministicKeyBuilder = value.getDeterministicKeyBuilder();
deterministicKeyBuilder.setChainCode(ByteString.copyFrom(deterministicKey.getChainCode()));
UnmodifiableIterator it = deterministicKey.getPath().iterator();
while (it.hasNext()) {
deterministicKeyBuilder.addPath(((ChildNumber) it.next()).i());
}
if (deterministicKey.equals(this.externalParentKey)) {
deterministicKeyBuilder.setIssuedSubkeys(this.issuedExternalKeys);
deterministicKeyBuilder.setLookaheadSize(this.lookaheadSize);
deterministicKeyBuilder.setSigsRequiredToSpend(getSigsRequiredToSpend());
} else if (deterministicKey.equals(this.internalParentKey)) {
deterministicKeyBuilder.setIssuedSubkeys(this.issuedInternalKeys);
deterministicKeyBuilder.setLookaheadSize(this.lookaheadSize);
deterministicKeyBuilder.setSigsRequiredToSpend(getSigsRequiredToSpend());
}
if (newLinkedList.isEmpty() && isFollowing()) {
deterministicKeyBuilder.setIsFollowing(true);
}
if (deterministicKey.getParent() != null) {
value.clearCreationTimestamp();
}
newLinkedList.add(value.m2291build());
}
return newLinkedList;
}
static List<DeterministicKeyChain> fromProtobuf(List<Protos.Key> list, @Nullable KeyCrypter keyCrypter) throws UnreadableWalletException {
return fromProtobuf(list, keyCrypter, new DefaultKeyChainFactory());
}
public static java.util.List<org.bitcoinj.wallet.DeterministicKeyChain> fromProtobuf(java.util.List<org.bitcoinj.wallet.Protos.Key> r27, @javax.annotation.Nullable org.bitcoinj.crypto.KeyCrypter r28, org.bitcoinj.wallet.KeyChainFactory r29) throws org.bitcoinj.wallet.UnreadableWalletException {
throw new UnsupportedOperationException("Method not decompiled: org.bitcoinj.wallet.DeterministicKeyChain.fromProtobuf(java.util.List, org.bitcoinj.crypto.KeyCrypter, org.bitcoinj.wallet.KeyChainFactory):java.util.List");
}
@Override
public DeterministicKeyChain toEncrypted(CharSequence charSequence) {
Preconditions.checkNotNull(charSequence);
Preconditions.checkArgument(charSequence.length() > 0);
Preconditions.checkState(this.seed != null, "Attempt to encrypt a watching chain.");
Preconditions.checkState(!this.seed.isEncrypted());
KeyCrypterScrypt keyCrypterScrypt = new KeyCrypterScrypt();
return toEncrypted((KeyCrypter) keyCrypterScrypt, keyCrypterScrypt.deriveKey(charSequence));
}
@Override
public DeterministicKeyChain toEncrypted(KeyCrypter keyCrypter, KeyParameter keyParameter) {
return new DeterministicKeyChain(keyCrypter, keyParameter, this);
}
@Override
public DeterministicKeyChain toDecrypted(CharSequence charSequence) {
Preconditions.checkNotNull(charSequence);
Preconditions.checkArgument(charSequence.length() > 0);
KeyCrypter keyCrypter = getKeyCrypter();
Preconditions.checkState(keyCrypter != null, "Chain not encrypted");
return toDecrypted(keyCrypter.deriveKey(charSequence));
}
@Override
public DeterministicKeyChain toDecrypted(KeyParameter keyParameter) {
Preconditions.checkState(getKeyCrypter() != null, "Key chain not encrypted");
Preconditions.checkState(this.seed != null, "Can't decrypt a watching chain");
Preconditions.checkState(this.seed.isEncrypted());
DeterministicKeyChain makeKeyChainFromSeed = makeKeyChainFromSeed(this.seed.decrypt(getKeyCrypter(), "", keyParameter));
if (!makeKeyChainFromSeed.getWatchingKey().getPubKeyPoint().equals(getWatchingKey().getPubKeyPoint())) {
throw new KeyCrypterException("Provided AES key is wrong");
}
makeKeyChainFromSeed.lookaheadSize = this.lookaheadSize;
Iterator<ECKey> it = this.basicKeyChain.getKeys().iterator();
while (it.hasNext()) {
DeterministicKey deterministicKey = (DeterministicKey) it.next();
if (deterministicKey.getPath().size() == getAccountPath().size() + 2) {
Preconditions.checkState(deterministicKey.isEncrypted());
DeterministicKey deterministicKey2 = new DeterministicKey(deterministicKey.dropPrivateBytes(), makeKeyChainFromSeed.hierarchy.get(((DeterministicKey) Preconditions.checkNotNull(deterministicKey.getParent())).getPath(), false, false));
makeKeyChainFromSeed.hierarchy.putKey(deterministicKey2);
makeKeyChainFromSeed.basicKeyChain.importKey(deterministicKey2);
}
}
makeKeyChainFromSeed.issuedExternalKeys = this.issuedExternalKeys;
makeKeyChainFromSeed.issuedInternalKeys = this.issuedInternalKeys;
return makeKeyChainFromSeed;
}
protected DeterministicKeyChain makeKeyChainFromSeed(DeterministicSeed deterministicSeed) {
return new DeterministicKeyChain(deterministicSeed);
}
@Override
public boolean checkPassword(CharSequence charSequence) {
Preconditions.checkNotNull(charSequence);
Preconditions.checkState(getKeyCrypter() != null, "Key chain not encrypted");
return checkAESKey(getKeyCrypter().deriveKey(charSequence));
}
@Override
public boolean checkAESKey(KeyParameter keyParameter) {
Preconditions.checkState(this.rootKey != null, "Can't check password for a watching chain");
Preconditions.checkNotNull(keyParameter);
Preconditions.checkState(getKeyCrypter() != null, "Key chain not encrypted");
try {
return this.rootKey.decrypt(keyParameter).getPubKeyPoint().equals(this.rootKey.getPubKeyPoint());
} catch (KeyCrypterException unused) {
return false;
}
}
@Override
@Nullable
public KeyCrypter getKeyCrypter() {
return this.basicKeyChain.getKeyCrypter();
}
@Override
public int numBloomFilterEntries() {
return numKeys() * 2;
}
@Override
public BloomFilter getFilter(int i, double d, long j) {
this.lock.lock();
try {
Preconditions.checkArgument(i >= numBloomFilterEntries());
maybeLookAhead();
return this.basicKeyChain.getFilter(i, d, j);
} finally {
this.lock.unlock();
}
}
public int getLookaheadSize() {
this.lock.lock();
try {
return this.lookaheadSize;
} finally {
this.lock.unlock();
}
}
public void setLookaheadSize(int i) {
this.lock.lock();
try {
boolean z = this.lookaheadThreshold == calcDefaultLookaheadThreshold();
this.lookaheadSize = i;
if (z) {
this.lookaheadThreshold = calcDefaultLookaheadThreshold();
}
} finally {
this.lock.unlock();
}
}
public void setLookaheadThreshold(int i) {
this.lock.lock();
try {
if (i >= this.lookaheadSize) {
throw new IllegalArgumentException("Threshold larger or equal to the lookaheadSize");
}
this.lookaheadThreshold = i;
} finally {
this.lock.unlock();
}
}
public int getLookaheadThreshold() {
this.lock.lock();
try {
return this.lookaheadThreshold >= this.lookaheadSize ? 0 : this.lookaheadThreshold;
} finally {
this.lock.unlock();
}
}
public void maybeLookAhead() {
this.lock.lock();
try {
List<DeterministicKey> maybeLookAhead = maybeLookAhead(this.externalParentKey, this.issuedExternalKeys);
maybeLookAhead.addAll(maybeLookAhead(this.internalParentKey, this.issuedInternalKeys));
if (maybeLookAhead.isEmpty()) {
return;
}
this.keyLookaheadEpoch++;
this.basicKeyChain.importKeys(maybeLookAhead);
} finally {
this.lock.unlock();
}
}
private List<DeterministicKey> maybeLookAhead(DeterministicKey deterministicKey, int i) {
Preconditions.checkState(this.lock.isHeldByCurrentThread());
return maybeLookAhead(deterministicKey, i, getLookaheadSize(), getLookaheadThreshold());
}
private List<DeterministicKey> maybeLookAhead(DeterministicKey deterministicKey, int i, int i2, int i3) {
Preconditions.checkState(this.lock.isHeldByCurrentThread());
int numChildren = this.hierarchy.getNumChildren(deterministicKey.getPath());
int i4 = ((i + i2) + i3) - numChildren;
if (i4 <= i3) {
return new ArrayList();
}
log.info("{} keys needed for {} = {} issued + {} lookahead size + {} lookahead threshold - {} num children", new Object[]{Integer.valueOf(i4), deterministicKey.getPathAsString(), Integer.valueOf(i), Integer.valueOf(i2), Integer.valueOf(i3), Integer.valueOf(numChildren)});
ArrayList arrayList = new ArrayList(i4);
Stopwatch createStarted = Stopwatch.createStarted();
for (int i5 = 0; i5 < i4; i5++) {
DeterministicKey dropPrivateBytes = HDKeyDerivation.deriveThisOrNextChildKey(deterministicKey, numChildren).dropPrivateBytes();
this.hierarchy.putKey(dropPrivateBytes);
arrayList.add(dropPrivateBytes);
numChildren = dropPrivateBytes.getChildNumber().num() + 1;
}
createStarted.stop();
log.info("Took {}", createStarted);
return arrayList;
}
public int getIssuedExternalKeys() {
this.lock.lock();
try {
return this.issuedExternalKeys;
} finally {
this.lock.unlock();
}
}
public int getIssuedInternalKeys() {
this.lock.lock();
try {
return this.issuedInternalKeys;
} finally {
this.lock.unlock();
}
}
@Nullable
public DeterministicSeed getSeed() {
this.lock.lock();
try {
return this.seed;
} finally {
this.lock.unlock();
}
}
List<ECKey> getKeys(boolean z) {
List<ECKey> keys = this.basicKeyChain.getKeys();
if (z) {
return keys;
}
int size = this.internalParentKey.getPath().size();
LinkedList linkedList = new LinkedList();
Iterator<ECKey> it = keys.iterator();
while (it.hasNext()) {
DeterministicKey deterministicKey = (DeterministicKey) it.next();
DeterministicKey parent = deterministicKey.getParent();
if (parent != null && deterministicKey.getPath().size() > size && (!parent.equals(this.internalParentKey) || deterministicKey.getChildNumber().i() < this.issuedInternalKeys)) {
if (!parent.equals(this.externalParentKey) || deterministicKey.getChildNumber().i() < this.issuedExternalKeys) {
linkedList.add(deterministicKey);
}
}
}
return linkedList;
}
public List<ECKey> getIssuedReceiveKeys() {
ArrayList arrayList = new ArrayList(getKeys(false));
Iterator it = arrayList.iterator();
while (it.hasNext()) {
DeterministicKey parent = ((DeterministicKey) it.next()).getParent();
if (parent == null || !this.externalParentKey.equals(parent)) {
it.remove();
}
}
return arrayList;
}
public List<DeterministicKey> getLeafKeys() {
ImmutableList.Builder builder = ImmutableList.builder();
Iterator<ECKey> it = getKeys(true).iterator();
while (it.hasNext()) {
DeterministicKey deterministicKey = (DeterministicKey) it.next();
if (deterministicKey.getPath().size() == getAccountPath().size() + 2) {
builder.add(deterministicKey);
}
}
return builder.build();
}
static void serializeSeedEncryptableItem(DeterministicSeed deterministicSeed, Protos.Key.Builder builder) {
if (deterministicSeed.isEncrypted() && deterministicSeed.getEncryptedSeedData() != null) {
EncryptedData encryptedSeedData = deterministicSeed.getEncryptedSeedData();
builder.getEncryptedDeterministicSeedBuilder().setEncryptedPrivateKey(ByteString.copyFrom(encryptedSeedData.encryptedBytes)).setInitialisationVector(ByteString.copyFrom(encryptedSeedData.initialisationVector));
Preconditions.checkState(deterministicSeed.getEncryptionType() == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES);
} else {
byte[] seedBytes = deterministicSeed.getSeedBytes();
if (seedBytes != null) {
builder.setDeterministicSeed(ByteString.copyFrom(seedBytes));
}
}
}
public int getKeyLookaheadEpoch() {
this.lock.lock();
try {
return this.keyLookaheadEpoch;
} finally {
this.lock.unlock();
}
}
public RedeemData getRedeemData(DeterministicKey deterministicKey) {
throw new UnsupportedOperationException();
}
public Script freshOutputScript(KeyChain.KeyPurpose keyPurpose) {
throw new UnsupportedOperationException();
}
public String toString(boolean z, NetworkParameters networkParameters) {
DeterministicKey watchingKey = getWatchingKey();
StringBuilder sb = new StringBuilder();
DeterministicSeed deterministicSeed = this.seed;
if (deterministicSeed != null) {
if (deterministicSeed.isEncrypted()) {
sb.append("Seed is encrypted\n");
} else if (z) {
List<String> mnemonicCode = this.seed.getMnemonicCode();
sb.append("Seed as words: ");
sb.append(Utils.join(mnemonicCode));
sb.append('\n');
sb.append("Seed as hex: ");
sb.append(this.seed.toHexString());
sb.append('\n');
}
sb.append("Seed birthday: ");
sb.append(this.seed.getCreationTimeSeconds());
sb.append(" [");
sb.append(Utils.dateTimeFormat(this.seed.getCreationTimeSeconds() * 1000));
sb.append("]\n");
} else {
sb.append("Key birthday: ");
sb.append(watchingKey.getCreationTimeSeconds());
sb.append(" [");
sb.append(Utils.dateTimeFormat(watchingKey.getCreationTimeSeconds() * 1000));
sb.append("]\n");
}
sb.append("Key to watch: ");
sb.append(watchingKey.serializePubB58(networkParameters));
sb.append('\n');
formatAddresses(z, networkParameters, sb);
return sb.toString();
}
protected void formatAddresses(boolean z, NetworkParameters networkParameters, StringBuilder sb) {
Iterator<ECKey> it = getKeys(false).iterator();
while (it.hasNext()) {
it.next().formatKeyWithAddress(z, sb, networkParameters);
}
}
public void setSigsRequiredToSpend(int i) {
this.sigsRequiredToSpend = i;
}
public int getSigsRequiredToSpend() {
return this.sigsRequiredToSpend;
}
}