/** * Derives a key given the "extended" child number, ie. the 0x80000000 bit of the value that you * pass for <code>childNumber</code> will determine whether to use hardened derivation or not. * Consider whether your code would benefit from the clarity of the equivalent, but explicit, form * of this method that takes a <code>ChildNumber</code> rather than an <code>int</code>, for example: * <code>deriveChildKey(parent, new ChildNumber(childNumber, true))</code> * where the value of the hardened bit of <code>childNumber</code> is zero. */ public static DeterministicKey deriveChildKey(DeterministicKey parent, int childNumber) { return deriveChildKey(parent, new ChildNumber(childNumber)); }
/** * Derives a key of the "extended" child number, ie. with the 0x80000000 bit specifying whether to use * hardened derivation or not. If derivation fails, tries a next child. */ public static DeterministicKey deriveThisOrNextChildKey(DeterministicKey parent, int childNumber) { int nAttempts = 0; ChildNumber child = new ChildNumber(childNumber); boolean isHardened = child.isHardened(); while (nAttempts < MAX_CHILD_DERIVATION_ATTEMPTS) { try { child = new ChildNumber(child.num() + nAttempts, isHardened); return deriveChildKey(parent, child); } catch (HDDerivationException ignore) { } nAttempts++; } throw new HDDerivationException("Maximum number of child derivation attempts reached, this is probably an indication of a bug."); }
public boolean isHardened() { return hasHardenedBit(i); }
@Override public String toString() { return String.format(Locale.US, "%d%s", num(), isHardened() ? "H" : ""); }
private ChildNumber getNextChildNumberToDerive(ImmutableList<ChildNumber> path, boolean privateDerivation) { ChildNumber lastChildNumber = lastChildNumbers.get(path); ChildNumber nextChildNumber = new ChildNumber(lastChildNumber != null ? lastChildNumber.num() + 1 : 0, privateDerivation); lastChildNumbers.put(path, nextChildNumber); return nextChildNumber; }
public int getNumChildren(ImmutableList<ChildNumber> path) { final ChildNumber cn = lastChildNumbers.get(path); if (cn == null) return 0; else return cn.num() + 1; // children start with zero based childnumbers }
public static RawKeyBytes deriveChildKeyBytesFromPrivate(DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException { checkArgument(parent.hasPrivKey(), "Parent key must have private key bytes for this method."); byte[] parentPublicKey = parent.getPubKeyPoint().getEncoded(true); checkState(parentPublicKey.length == 33, "Parent pubkey must be 33 bytes, but is " + parentPublicKey.length); ByteBuffer data = ByteBuffer.allocate(37); if (childNumber.isHardened()) { data.put(parent.getPrivKeyBytes33()); } else { data.put(parentPublicKey); } data.putInt(childNumber.i()); byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array()); checkState(i.length == 64, i.length); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] chainCode = Arrays.copyOfRange(i, 32, 64); BigInteger ilInt = new BigInteger(1, il); assertLessThanN(ilInt, "Illegal derived key: I_L >= n"); final BigInteger priv = parent.getPrivKey(); BigInteger ki = priv.add(ilInt).mod(ECKey.CURVE.getN()); assertNonZero(ki, "Illegal derived key: derived private key equals 0."); return new RawKeyBytes(ki.toByteArray(), chainCode); }
if (ChildNumber.ZERO_HARDENED.equals(firstLeafKeyPath.get(0))) { inferredWalletType = WalletType.MBHD_SOFT_WALLET_BIP32; } else if ((new ChildNumber(44 | ChildNumber.HARDENED_BIT)).equals(firstLeafKeyPath.get(0))) {
private byte[] serialize(NetworkParameters params, boolean pub) { ByteBuffer ser = ByteBuffer.allocate(78); ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv()); ser.put((byte) getDepth()); ser.putInt(getParentFingerprint()); ser.putInt(getChildNumber().i()); ser.put(getChainCode()); ser.put(pub ? getPubKey() : getPrivKeyBytes33()); checkState(ser.position() == 78); return ser.array(); }
/** Create a new married key and return the matching output script */ @Override public Script freshOutputScript(KeyPurpose purpose) { DeterministicKey followedKey = getKey(purpose); ImmutableList.Builder<ECKey> keys = ImmutableList.<ECKey>builder().add(followedKey); for (DeterministicKeyChain keyChain : followingKeyChains) { DeterministicKey followingKey = keyChain.getKey(purpose); checkState(followedKey.getChildNumber().equals(followingKey.getChildNumber()), "Following keychains should be in sync"); keys.add(followingKey); } List<ECKey> marriedKeys = keys.build(); Script redeemScript = ScriptBuilder.createRedeemScript(sigsRequiredToSpend, marriedKeys); return ScriptBuilder.createP2SHOutputScript(redeemScript); }
@Override public int compare(ECKey k1, ECKey k2) { ChildNumber cn1 = ((DeterministicKey) k1).getChildNumber(); ChildNumber cn2 = ((DeterministicKey) k2).getChildNumber(); return cn1.compareTo(cn2); } };
/** * <p>Build an AddressN chain code structure</p> * * @param receivingAddressPath The Bitcoinj receiving address path * * @return The list representing the chain code (only a simple chain is currently supported) */ public static List<Integer> buildAddressN(ImmutableList<ChildNumber> receivingAddressPath) { List<Integer> addressN = Lists.newArrayList(); for (ChildNumber childNumber : receivingAddressPath) { addressN.add(childNumber.getI()); } return addressN; }
private ChildNumber getNextChildNumberToDerive(ImmutableList<ChildNumber> path, boolean privateDerivation) { ChildNumber lastChildNumber = lastChildNumbers.get(path); ChildNumber nextChildNumber = new ChildNumber(lastChildNumber != null ? lastChildNumber.num() + 1 : 0, privateDerivation); lastChildNumbers.put(path, nextChildNumber); return nextChildNumber; }
public int getNumChildren(ImmutableList<ChildNumber> path) { final ChildNumber cn = lastChildNumbers.get(path); if (cn == null) return 0; else return cn.num() + 1; // children start with zero based childnumbers }
public static RawKeyBytes deriveChildKeyBytesFromPrivate(DeterministicKey parent, ChildNumber childNumber) throws HDDerivationException { checkArgument(parent.hasPrivKey(), "Parent key must have private key bytes for this method."); byte[] parentPublicKey = parent.getPubKeyPoint().getEncoded(true); checkState(parentPublicKey.length == 33, "Parent pubkey must be 33 bytes, but is " + parentPublicKey.length); ByteBuffer data = ByteBuffer.allocate(37); if (childNumber.isHardened()) { data.put(parent.getPrivKeyBytes33()); } else { data.put(parentPublicKey); } data.putInt(childNumber.i()); byte[] i = HDUtils.hmacSha512(parent.getChainCode(), data.array()); checkState(i.length == 64, i.length); byte[] il = Arrays.copyOfRange(i, 0, 32); byte[] chainCode = Arrays.copyOfRange(i, 32, 64); BigInteger ilInt = new BigInteger(1, il); assertLessThanN(ilInt, "Illegal derived key: I_L >= n"); final BigInteger priv = parent.getPrivKey(); BigInteger ki = priv.add(ilInt).mod(ECKey.CURVE.getN()); assertNonZero(ki, "Illegal derived key: derived private key equals 0."); return new RawKeyBytes(ki.toByteArray(), chainCode); }
@Override public String toString() { return String.format(Locale.US, "%d%s", num(), isHardened() ? "H" : ""); }
private byte[] serialize(NetworkParameters params, boolean pub) { ByteBuffer ser = ByteBuffer.allocate(78); ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv()); ser.put((byte) getDepth()); ser.putInt(getParentFingerprint()); ser.putInt(getChildNumber().i()); ser.put(getChainCode()); ser.put(pub ? getPubKey() : getPrivKeyBytes33()); checkState(ser.position() == 78); return ser.array(); }
/** Create a new married key and return the matching output script */ @Override public Script freshOutputScript(KeyPurpose purpose) { DeterministicKey followedKey = getKey(purpose); ImmutableList.Builder<ECKey> keys = ImmutableList.<ECKey>builder().add(followedKey); for (DeterministicKeyChain keyChain : followingKeyChains) { DeterministicKey followingKey = keyChain.getKey(purpose); checkState(followedKey.getChildNumber().equals(followingKey.getChildNumber()), "Following keychains should be in sync"); keys.add(followingKey); } List<ECKey> marriedKeys = keys.build(); Script redeemScript = ScriptBuilder.createRedeemScript(sigsRequiredToSpend, marriedKeys); return ScriptBuilder.createP2SHOutputScript(redeemScript); }
@Override public int compare(ECKey k1, ECKey k2) { ChildNumber cn1 = ((DeterministicKey) k1).getChildNumber(); ChildNumber cn2 = ((DeterministicKey) k2).getChildNumber(); return cn1.compareTo(cn2); } };
/** * <p>Build an AddressN chain code structure</p> * * @param receivingAddressPath The Bitcoinj receiving address path * * @return The list representing the chain code (only a simple chain is currently supported) */ public static List<Integer> buildAddressN(ImmutableList<ChildNumber> receivingAddressPath) { List<Integer> addressN = Lists.newArrayList(); for (ChildNumber childNumber : receivingAddressPath) { addressN.add(childNumber.getI()); } return addressN; }