public BitWalletSingleKey(CoinType coinType, ECKey key) { super(checkNotNull(coinType), Wallet.generateRandomId()); keys = new SimpleKeyChain(); keys.importKey(key); }
@Override public void addEventListener(KeyChainEventListener listener, Executor executor) { simpleKeyChain.addEventListener(listener, executor); }
@Override public DeterministicKey findKeyFromPubHash(byte[] pubkeyHash) { lock.lock(); try { return (DeterministicKey) simpleKeyChain.findKeyFromPubHash(pubkeyHash); } finally { lock.unlock(); } }
private SimpleHDKeyChain(KeyCrypter crypter, KeyParameter aesKey, SimpleHDKeyChain chain) { checkArgument(!chain.rootKey.isEncrypted(), "Chain already encrypted"); this.issuedExternalKeys = chain.issuedExternalKeys; this.issuedInternalKeys = chain.issuedInternalKeys; this.lookaheadSize = chain.lookaheadSize; this.lookaheadThreshold = chain.lookaheadThreshold; simpleKeyChain = new SimpleKeyChain(crypter); // The first number is the "account number" but we don't use that feature. rootKey = chain.rootKey.encrypt(crypter, aesKey, null); hierarchy = new DeterministicHierarchy(rootKey); simpleKeyChain.importKey(rootKey); externalKey = encryptNonLeaf(aesKey, chain, rootKey, EXTERNAL_PATH); internalKey = encryptNonLeaf(aesKey, chain, rootKey, INTERNAL_PATH); // Now copy the (pubkey only) leaf keys across to avoid rederiving them. The private key bytes are missing // anyway so there's nothing to encrypt. for (ECKey eckey : chain.simpleKeyChain.getKeys()) { DeterministicKey key = (DeterministicKey) eckey; if (!isLeaf(key)) continue; // Not a leaf key. DeterministicKey parent = hierarchy.get(checkNotNull(key.getParent(), "Key has no parent").getPath(), false, false); // Clone the key to the new encrypted hierarchy. key = new DeterministicKey(key.getPubOnly(), parent); hierarchy.putKey(key); simpleKeyChain.importKey(key); } }
private DeterministicKey encryptNonLeaf(KeyParameter aesKey, SimpleHDKeyChain chain, DeterministicKey parent, ImmutableList<ChildNumber> path) { DeterministicKey key = chain.hierarchy.get(path, true, false); key = key.encrypt(checkNotNull(simpleKeyChain.getKeyCrypter(), "Chain has null KeyCrypter"), aesKey, parent); hierarchy.putKey(key); simpleKeyChain.importKey(key); return key; }
@Override public SimpleHDKeyChain toDecrypted(KeyParameter aesKey) { checkState(getKeyCrypter() != null, "Key chain not encrypted"); checkState(rootKey.isEncrypted(), "Root key not encrypted"); DeterministicKey decKey = rootKey.decrypt(getKeyCrypter(), aesKey); SimpleHDKeyChain chain = new SimpleHDKeyChain(decKey); // 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())) throw new KeyCrypterException("Provided AES key is wrong"); chain.lookaheadSize = lookaheadSize; // Now copy the (pubkey only) leaf keys across to avoid rederiving them. The private key bytes are missing // anyway so there's nothing to decrypt. for (ECKey eckey : simpleKeyChain.getKeys()) { DeterministicKey key = (DeterministicKey) eckey; if (!isLeaf(key)) continue; // Not a leaf key. checkState(key.isEncrypted(), "Key is not encrypted"); DeterministicKey parent = chain.hierarchy.get(checkNotNull(key.getParent(), "Key has null parent").getPath(), false, false); // Clone the key to the new decrypted hierarchy. key = new DeterministicKey(key.getPubOnly(), parent); chain.hierarchy.putKey(key); chain.simpleKeyChain.importKeys(key); } chain.issuedExternalKeys = issuedExternalKeys; chain.issuedInternalKeys = issuedInternalKeys; return chain; }
Map<ECKey, Protos.Key.Builder> toEditableProtobufs() { Map<ECKey, Protos.Key.Builder> result = new LinkedHashMap<ECKey, Protos.Key.Builder>(); for (ECKey ecKey : getKeys()) { Protos.Key.Builder protoKey = KeyUtils.serializeKey(ecKey); result.put(ecKey, protoKey); } return result; } }
@Override public DeterministicKey findKeyFromPubKey(byte[] pubkey) { lock.lock(); try { return (DeterministicKey) simpleKeyChain.findKeyFromPubKey(pubkey); } finally { lock.unlock(); } }
@Override public byte[] getPublicKey() { lock.lock(); try { return keys.getKey(null).getPubKey(); } finally { lock.unlock(); } }
/** * Creates a deterministic key chain that watches the given (public only) root key. You can use this to calculate * balances and generally follow along, but spending is not possible with such a chain. Currently you can't use * this method to watch an arbitrary fragment of some other tree, this limitation may be removed in future. */ public SimpleHDKeyChain(DeterministicKey rootkey) { simpleKeyChain = new SimpleKeyChain(); initializeHierarchyUnencrypted(rootkey); }
@Nullable @Override public KeyCrypter getKeyCrypter() { return simpleKeyChain.getKeyCrypter(); }
@Override public boolean hasKey(ECKey key) { lock.lock(); try { return simpleKeyChain.hasKey(key); } finally { lock.unlock(); } }
@Override public BloomFilter getFilter(int size, double falsePositiveRate, long tweak) { lock.lock(); try { checkArgument(size >= numBloomFilterEntries(), "Bloom filter too small"); maybeLookAhead(); return simpleKeyChain.getFilter(size, falsePositiveRate, tweak); } finally { lock.unlock(); } }
chain.simpleKeyChain.importKey(detkey);
@Override public List<AbstractAddress> getActiveAddresses() { lock.lock(); try { ImmutableList.Builder<AbstractAddress> activeAddresses = ImmutableList.builder(); for (ECKey key : keys.getKeys()) { activeAddresses.add(BitAddress.from(type, key)); } return activeAddresses.build(); } finally { lock.unlock(); } }
@Nullable @Override public ECKey findKeyFromPubKey(byte[] pubkey) { lock.lock(); try { return keys.findKeyFromPubKey(pubkey); } finally { lock.unlock(); } }
@Override public AbstractAddress getReceiveAddress() { lock.lock(); try { return BitAddress.from(type, keys.getKey(null)); } finally { lock.unlock(); } }
SimpleHDKeyChain(DeterministicKey rootkey, @Nullable KeyCrypter crypter) { this.rootKey = rootkey; simpleKeyChain = new SimpleKeyChain(crypter); if (!rootkey.isEncrypted()) { initializeHierarchyUnencrypted(rootKey); } // Else... // We can't initialize ourselves with just an encrypted seed, so we expected deserialization code to do the // rest of the setup (loading the root key). }
/** * Returns keys used on external path. This may be fewer than the number that have been deserialized * or held in memory, because of the lookahead zone. */ public ArrayList<DeterministicKey> getIssuedExternalKeys() { lock.lock(); try { maybeLookAhead(); int treeSize = externalKey.getPath().size(); ArrayList<DeterministicKey> issuedKeys = new ArrayList<DeterministicKey>(); for (ECKey key : simpleKeyChain.getKeys()) { DeterministicKey detkey = (DeterministicKey) key; DeterministicKey parent = detkey.getParent(); if (parent == null) continue; if (detkey.getPath().size() <= treeSize) continue; if (parent.equals(internalKey)) continue; if (parent.equals(externalKey) && detkey.getChildNumber().num() >= issuedExternalKeys) continue; issuedKeys.add(detkey); } return issuedKeys; } finally { lock.unlock(); } }
/** * Mark the DeterministicKeys as used, if they match the pubkey * See {@link SimpleHDKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this. */ public boolean markPubKeyAsUsed(byte[] pubkey) { lock.lock(); try { DeterministicKey k = (DeterministicKey) simpleKeyChain.findKeyFromPubKey(pubkey); if (k != null) markKeyAsUsed(k); return k != null; } finally { lock.unlock(); } }