Skip to content

Instantly share code, notes, and snippets.

@devrandom
Forked from anonymous/HDUtil.java
Created December 5, 2014 18:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devrandom/15ca7c9759029798e0e9 to your computer and use it in GitHub Desktop.
Save devrandom/15ca7c9759029798e0e9 to your computer and use it in GitHub Desktop.
Parse Bitcoin extended keys
public class HDUtil {
private static final byte[] xprv = new byte[]{0x04, (byte) 0x88, (byte) 0xAD, (byte) 0xE4};
private static final byte[] xpub = new byte[]{0x04, (byte) 0x88, (byte) 0xB2, (byte) 0x1E};
private static final byte[] tprv = new byte[]{0x04, (byte) 0x35, (byte) 0x83, (byte) 0x94};
private static final byte[] tpub = new byte[]{0x04, (byte) 0x35, (byte) 0x87, (byte) 0xCF};
public static DeterministicKey parseDeterministicKey(String serialized) throws AddressFormatException {
byte[] data = Base58.decodeChecked(serialized);
if (data.length != 78) {
throw new AddressFormatException("invalid extended key");
}
byte[] type = Arrays.copyOf(data, 4);
boolean hasPrivate;
if (Arrays.equals(type, xprv) || Arrays.equals(type, tprv)) {
hasPrivate = true;
} else if (Arrays.equals(type, xpub) || Arrays.equals(type, tpub)) {
hasPrivate = false;
} else {
throw new AddressFormatException("invalid magic number for an extended key");
}
int depth = data[4] & 0xff;
int parent = data[5] & 0xff;
parent <<= 8;
parent |= data[6] & 0xff;
parent <<= 8;
parent |= data[7] & 0xff;
parent <<= 8;
parent |= data[8] & 0xff;
int sequence = data[9] & 0xff;
sequence <<= 8;
sequence |= data[10] & 0xff;
sequence <<= 8;
sequence |= data[11] & 0xff;
sequence <<= 8;
sequence |= data[12] & 0xff;
// Ignore depth, parent, sequence for now
byte[] chainCode = Arrays.copyOfRange(data, 13, 13 + 32);
byte[] pubOrPriv = Arrays.copyOfRange(data, 13 + 32, data.length);
DeterministicKey key;
ImmutableList<ChildNumber> childPath = ImmutableList.of();
if (hasPrivate) {
key = new DeterministicKey(childPath, chainCode, new BigInteger(1, pubOrPriv), null);
} else {
key = new DeterministicKey(childPath, chainCode, ECKey.CURVE.getCurve().decodePoint(pubOrPriv), null, null);
}
return key;
}
public static List<ChildNumber> parseChainPath(String chainPath) {
if (chainPath.isEmpty())
return Lists.newArrayList();
String[] components = chainPath.split("/");
List<ChildNumber> result = Lists.newArrayListWithExpectedSize(components.length);
for (int i = 0; i < components.length; i++) {
String component = components[i];
boolean prime = false;
if (component.endsWith("'")) {
component = component.substring(0, component.length() - 1);
prime = true;
}
result.add(new ChildNumber(Integer.valueOf(component), prime));
}
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment