@Nullable @Override public ECKey findKeyFromPubKey(byte[] pubkey) { ECKey result; if ((result = basic.findKeyFromPubKey(pubkey)) != null) return result; for (DeterministicKeyChain chain : chains) { if ((result = chain.findKeyFromPubKey(pubkey)) != null) return result; } return null; }
@Nullable @Override public ECKey findKeyFromPubHash(byte[] pubkeyHash) { ECKey result; if ((result = basic.findKeyFromPubHash(pubkeyHash)) != null) return result; for (DeterministicKeyChain chain : chains) { if ((result = chain.findKeyFromPubHash(pubkeyHash)) != null) return result; } return null; }
private static EnumMap<KeyChain.KeyPurpose, DeterministicKey> createCurrentKeysMap(List<DeterministicKeyChain> chains) { DeterministicKeyChain activeChain = chains.get(chains.size() - 1); EnumMap<KeyChain.KeyPurpose, DeterministicKey> currentKeys = new EnumMap<KeyChain.KeyPurpose, DeterministicKey>(KeyChain.KeyPurpose.class); // assuming that only RECEIVE and CHANGE keys are being used at the moment, we will treat latest issued external key // as current RECEIVE key and latest issued internal key as CHANGE key. This should be changed as soon as other // kinds of KeyPurpose are introduced. if (activeChain.getIssuedExternalKeys() > 0) { DeterministicKey currentExternalKey = activeChain.getKeyByPath( HDUtils.append( HDUtils.concat(activeChain.getAccountPath(), DeterministicKeyChain.EXTERNAL_SUBPATH), new ChildNumber(activeChain.getIssuedExternalKeys() - 1))); currentKeys.put(KeyChain.KeyPurpose.RECEIVE_FUNDS, currentExternalKey); } if (activeChain.getIssuedInternalKeys() > 0) { DeterministicKey currentInternalKey = activeChain.getKeyByPath( HDUtils.append( HDUtils.concat(activeChain.getAccountPath(), DeterministicKeyChain.INTERNAL_SUBPATH), new ChildNumber(activeChain.getIssuedInternalKeys() - 1))); currentKeys.put(KeyChain.KeyPurpose.CHANGE, currentInternalKey); } return currentKeys; }
/** * <p>An alias for <code>getKeyByPath(getAccountPath())</code>.</p> * * <p>Use this when you would like to create a watching key chain that follows this one, but can't spend money from it. * The returned key can be serialized and then passed into {@link #watch(org.bitcoinj.crypto.DeterministicKey)} * on another system to watch the hierarchy.</p> * * <p>Note that the returned key is not pubkey only unless this key chain already is: the returned key can still * be used for signing etc if the private key bytes are available.</p> */ public DeterministicKey getWatchingKey() { return getKeyByPath(getAccountPath()); }
@Override public boolean checkPassword(CharSequence password) { checkNotNull(password); checkState(getKeyCrypter() != null, "Key chain not encrypted"); return checkAESKey(getKeyCrypter().deriveKey(password)); }
private void initializeHierarchyUnencrypted(DeterministicKey baseKey) { externalParentKey = hierarchy.deriveChild(getAccountPath(), false, false, ChildNumber.ZERO); internalParentKey = hierarchy.deriveChild(getAccountPath(), false, false, ChildNumber.ONE); addToBasicChain(externalParentKey); addToBasicChain(internalParentKey); }
@Test public void encryption() throws UnreadableWalletException { DeterministicKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKeyChain encChain = chain.toEncrypted("open secret"); DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey()); checkEncryptedKeyChain(encChain, key1); List<Protos.Key> serialized = encChain.serializeToProtobuf(); List<Protos.Key> doubled = Lists.newArrayListWithExpectedSize(serialized.size() * 2); doubled.addAll(serialized); doubled.addAll(serialized); final List<DeterministicKeyChain> chains = DeterministicKeyChain.fromProtobuf(doubled, encChain.getKeyCrypter()); assertEquals(2, chains.size()); encChain = chains.get(0); checkEncryptedKeyChain(encChain, chain.findKeyFromPubKey(key1.getPubKey())); encChain = chains.get(1); checkEncryptedKeyChain(encChain, chain.findKeyFromPubKey(key1.getPubKey())); DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKeyChain decChain = encChain.toDecrypted("open secret"); DeterministicKey decKey1 = decChain.findKeyFromPubHash(encKey1.getPubKeyHash()); DeterministicKey decKey2 = decChain.findKeyFromPubHash(encKey2.getPubKeyHash()); assertEquals(decKey1.getPubKeyPoint(), encKey1.getPubKeyPoint()); assertEquals(decKey2.getPubKeyPoint(), encKey2.getPubKeyPoint()); decChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).sign(Sha256Hash.ZERO_HASH); decChain.getKey(KeyChain.KeyPurpose.CHANGE).sign(Sha256Hash.ZERO_HASH);
@Test public void watchingChain() throws UnreadableWalletException { Utils.setMockClock(); DeterministicKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key2 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key3 = chain.getKey(KeyChain.KeyPurpose.CHANGE); DeterministicKey key4 = chain.getKey(KeyChain.KeyPurpose.CHANGE); DeterministicKey watchingKey = chain.getWatchingKey(); final String pub58 = watchingKey.serializePubB58(params); assertEquals("xpub69KR9epSNBM59KLuasxMU5CyKytMJjBP5HEZ5p8YoGUCpM6cM9hqxB9DDPCpUUtqmw5duTckvPfwpoWGQUFPmRLpxs5jYiTf2u6xRMcdhDf", pub58); watchingKey = DeterministicKey.deserializeB58(null, pub58, params); watchingKey.setCreationTimeSeconds(100000); chain = DeterministicKeyChain.watch(watchingKey); assertEquals(100000, chain.getEarliestKeyCreationTime()); chain.setLookaheadSize(10); chain.maybeLookAhead(); assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint()); assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint()); final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint()); try { List<Protos.Key> serialization = chain.serializeToProtobuf(); checkSerialization(serialization, "watching-wallet-serialization.txt"); chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0); final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
@Test public void serializeUnencrypted() throws UnreadableWalletException { chain.maybeLookAhead(); DeterministicKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key2 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key3 = chain.getKey(KeyChain.KeyPurpose.CHANGE); List<Protos.Key> keys = chain.serializeToProtobuf(); + 1 // account key + 2 // ext/int parent keys + (chain.getLookaheadSize() + chain.getLookaheadThreshold()) * 2 // lookahead zone on each chain DeterministicKey key4 = chain.getKey(KeyChain.KeyPurpose.CHANGE); int oldLookaheadSize = chain.getLookaheadSize(); chain = DeterministicKeyChain.fromProtobuf(keys, null).get(0); assertEquals(EXPECTED_SERIALIZATION, protoToString(chain.serializeToProtobuf())); assertEquals(key1, chain.findKeyFromPubHash(key1.getPubKeyHash())); assertEquals(key2, chain.findKeyFromPubHash(key2.getPubKeyHash())); assertEquals(key3, chain.findKeyFromPubHash(key3.getPubKeyHash())); assertEquals(key4, chain.getKey(KeyChain.KeyPurpose.CHANGE)); key1.sign(Sha256Hash.ZERO_HASH); key2.sign(Sha256Hash.ZERO_HASH); key3.sign(Sha256Hash.ZERO_HASH); key4.sign(Sha256Hash.ZERO_HASH); assertEquals(oldLookaheadSize, chain.getLookaheadSize());
chain = new DeterministicKeyChain(ENTROPY, "", secs); chain.addEventListener(new AbstractKeyChainEventListener() { @Override public void onKeysAdded(List<ECKey> keys) { chain.setLookaheadSize(5); assertEquals(0, listenerKeys.size()); ECKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals(1, listenerKeys.size()); // 1 event final List<ECKey> firstEvent = listenerKeys.get(0); chain.maybeLookAhead(); final List<ECKey> secondEvent = listenerKeys.get(0); assertEquals(12, secondEvent.size()); // (5 lookahead keys, +1 lookahead threshold) * 2 chains listenerKeys.clear(); chain.getKey(KeyChain.KeyPurpose.CHANGE); final int lookaheadThreshold = chain.getLookaheadThreshold() + chain.getLookaheadSize(); for (int i = 0; i < lookaheadThreshold; i++) chain.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals(1, listenerKeys.size()); // 1 event assertEquals(1, listenerKeys.get(0).size()); // 1 key.
@Test public void serializeAccountOne() throws Exception { long secs = 1389353062L; DeterministicKeyChain chain1 = new AccountOneChain(ENTROPY, "", secs); ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); final Address address = Address.fromBase58(UnitTestParams.get(), "n2nHHRHs7TiZScTuVhZUkzZfTfVgGYwy6X"); assertEquals(address, key1.toAddress(UnitTestParams.get())); DeterministicKey watching = chain1.getWatchingKey(); List<Protos.Key> keys = chain1.serializeToProtobuf(); KeyChainFactory factory = new KeyChainFactory() { @Override public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed, KeyCrypter crypter, boolean isMarried) { return new AccountOneChain(crypter, seed); } @Override public DeterministicKeyChain makeWatchingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey, boolean isFollowingKey, boolean isMarried) { throw new UnsupportedOperationException(); } }; chain1 = DeterministicKeyChain.fromProtobuf(keys, null, factory).get(0); ECKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); assertEquals("mnp2j9za5zMuz44vNxrJCXXhZsCdh89QXn", key2.toAddress(UnitTestParams.get()).toString()); assertEquals(key1, chain1.findKeyFromPubHash(address.getHash160())); assertEquals(key2, chain1.findKeyFromPubKey(key2.getPubKey())); key1.sign(Sha256Hash.ZERO_HASH); ECKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals("mpjRhk13rvV7vmnszcUQVYVQzy4HLTPTQU", key3.toAddress(UnitTestParams.get()).toString()); key3.sign(Sha256Hash.ZERO_HASH); assertEquals(watching, chain1.getWatchingKey()); }
private void checkEncryptedKeyChain(DeterministicKeyChain encChain, DeterministicKey key1) { // Check we can look keys up and extend the chain without the AES key being provided. DeterministicKey encKey1 = encChain.findKeyFromPubKey(key1.getPubKey()); DeterministicKey encKey2 = encChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); assertFalse(key1.isEncrypted()); assertTrue(encKey1.isEncrypted()); assertEquals(encKey1.getPubKeyPoint(), key1.getPubKeyPoint()); final KeyParameter aesKey = checkNotNull(encChain.getKeyCrypter()).deriveKey("open secret"); encKey1.sign(Sha256Hash.ZERO_HASH, aesKey); encKey2.sign(Sha256Hash.ZERO_HASH, aesKey); assertTrue(encChain.checkAESKey(aesKey)); assertFalse(encChain.checkPassword("access denied")); assertTrue(encChain.checkPassword("open secret")); }
/** * Adds an HD chain to the chains list, and make it the default chain (from which keys are issued). * Useful for adding a complex pre-configured keychain, such as a married wallet. */ public void addAndActivateHDChain(DeterministicKeyChain chain) { log.info("Creating and activating a new HD chain: {}", chain); for (ListenerRegistration<KeyChainEventListener> registration : basic.getListeners()) chain.addEventListener(registration.listener, registration.executor); if (lookaheadSize >= 0) chain.setLookaheadSize(lookaheadSize); if (lookaheadThreshold >= 0) chain.setLookaheadThreshold(lookaheadThreshold); chains.add(chain); }
@Test public void deriveAccountOne() throws Exception { long secs = 1389353062L; DeterministicKeyChain chain1 = new AccountOneChain(ENTROPY, "", secs); ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); ECKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); final Address address = Address.fromBase58(UnitTestParams.get(), "n2nHHRHs7TiZScTuVhZUkzZfTfVgGYwy6X"); assertEquals(address, key1.toAddress(UnitTestParams.get())); assertEquals("mnp2j9za5zMuz44vNxrJCXXhZsCdh89QXn", key2.toAddress(UnitTestParams.get()).toString()); assertEquals(key1, chain1.findKeyFromPubHash(address.getHash160())); assertEquals(key2, chain1.findKeyFromPubKey(key2.getPubKey())); key1.sign(Sha256Hash.ZERO_HASH); ECKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE); assertEquals("mpjRhk13rvV7vmnszcUQVYVQzy4HLTPTQU", key3.toAddress(UnitTestParams.get()).toString()); key3.sign(Sha256Hash.ZERO_HASH); }
@Before public void setup() { BriefLogFormatter.init(); // 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(ENTROPY, "", secs); chain.setLookaheadSize(10); assertEquals(secs, checkNotNull(chain.getSeed()).getCreationTimeSeconds()); }
public void markP2SHAddressAsUsed(Address address) { checkArgument(address.isP2SHAddress()); RedeemData data = findRedeemDataFromScriptHash(address.getHash160()); if (data == null) return; // Not our P2SH address. for (ECKey key : data.keys) { for (DeterministicKeyChain chain : chains) { DeterministicKey k = chain.findKeyFromPubKey(key.getPubKey()); if (k == null) continue; chain.markKeyAsUsed(k); maybeMarkCurrentAddressAsUsed(address); } } }
/** * Returns leaf keys issued by this chain (including lookahead zone) */ public List<DeterministicKey> getLeafKeys() { ImmutableList.Builder<DeterministicKey> keys = ImmutableList.builder(); for (ECKey key : getKeys(true, false)) { DeterministicKey dKey = (DeterministicKey) key; if (dKey.getPath().size() == getAccountPath().size() + 2) { keys.add(dKey); } } return keys.build(); }
/** * Returns the immutable seed for the current active HD chain. * @throws org.bitcoinj.core.ECKey.MissingPrivateKeyException if the seed is unavailable (watching wallet) */ public DeterministicSeed getKeyChainSeed() { keyChainGroupLock.lock(); try { DeterministicSeed seed = keyChainGroup.getActiveKeyChain().getSeed(); if (seed == null) throw new ECKey.MissingPrivateKeyException(); return seed; } finally { keyChainGroupLock.unlock(); } }
static List<DeterministicKeyChain> fromProtobuf(List<Protos.Key> keys, @Nullable KeyCrypter crypter, boolean useSegwit) throws UnreadableWalletException { return fromProtobuf(keys, crypter, new DefaultKeyChainFactory(), useSegwit); }
key = Optional.fromNullable(activeKeyChain.findKeyFromPubKey(pubkey)); ECKey ecKey = ECKey.fromPublicOnly(pubkey); address = Optional.fromNullable(ecKey.toAddress(MainNetParams.get())); key = Optional.fromNullable(activeKeyChain.findKeyFromPubHash(pubkeyHash)); address = Optional.fromNullable(new Address(MainNetParams.get(), pubkeyHash)); } else { key = Optional.fromNullable(activeKeyChain.findKeyFromPubHash(pubkeyHash)); address = Optional.fromNullable(new Address(MainNetParams.get(), pubkeyHash));