Commit 52f03cfb authored by T Dev. D's avatar T Dev. D 😎
Browse files

BIP49 derivation scheme changes: ypub, yprv, upub, uprv

parent 2ac47850
......@@ -90,6 +90,10 @@ public abstract class NetworkParameters {
protected byte[] alertSigningKey;
protected int bip32HeaderPub;
protected int bip32HeaderPriv;
protected int bip49HeaderPub;
protected int bip49HeaderPriv;
protected int bip141HeaderPub;
protected int bip141HeaderPriv;
/** Used to check majorities for block version upgrade */
protected int majorityEnforceBlockUpgrade;
......@@ -107,7 +111,7 @@ public abstract class NetworkParameters {
*/
protected int spendableCoinbaseDepth;
protected int subsidyDecreaseBlockCount;
protected int[] acceptableAddressCodes;
protected String[] dnsSeeds;
protected int[] addrSeeds;
......@@ -146,7 +150,7 @@ public abstract class NetworkParameters {
public static final int TARGET_TIMESPAN = 14 * 24 * 60 * 60; // 2 weeks per difficulty cycle, on average.
public static final int TARGET_SPACING = 10 * 60; // 10 minutes per block.
public static final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
/**
* Blocks with a timestamp after this should enforce BIP 16, aka "Pay to script hash". This BIP changed the
* network rules in a soft-forking manner, that is, blocks that don't follow the rules are accepted but not
......@@ -406,6 +410,16 @@ public abstract class NetworkParameters {
return bip32HeaderPriv;
}
/** Returns the 4 byte header for BIP49 (HD) wallet - public key part. */
public int getBip49HeaderPub() {
return bip49HeaderPub;
}
/** Returns the 4 byte header for BIP49 (HD) wallet - private key part. */
public int getBip49HeaderPriv() {
return bip49HeaderPriv;
}
/**
* Returns the number of coins that will be produced in total, on this
* network. Where not applicable, a very large number of coins is returned
......@@ -438,7 +452,7 @@ public abstract class NetworkParameters {
/**
* Return the default serializer for this network. This is a shared serializer.
* @return
* @return
*/
public final MessageSerializer getDefaultSerializer() {
// Construct a default serializer if we don't have one
......@@ -493,7 +507,7 @@ public abstract class NetworkParameters {
* The flags indicating which block validation tests should be applied to
* the given block. Enables support for alternative blockchains which enable
* tests based on different criteria.
*
*
* @param block block to determine flags for.
* @param height height of the block, if known, null otherwise. Returned
* tests should be a safe subset if block height is unknown.
......
......@@ -165,7 +165,7 @@ public class DeterministicKey extends ECKey {
this.parentFingerprint = ascertainParentFingerprint(parent, parentFingerprint);
}
/** Clones the key */
public DeterministicKey(DeterministicKey keyToClone, DeterministicKey newParent) {
super(keyToClone.priv, keyToClone.pub.get());
......@@ -461,17 +461,22 @@ public class DeterministicKey extends ECKey {
return key;
}
public byte[] serializePublic(NetworkParameters params) {
return serialize(params, true);
public byte[] serializePublic(NetworkParameters params, boolean bip49) {
return serialize(params, true, bip49);
}
public byte[] serializePrivate(NetworkParameters params) {
return serialize(params, false);
public byte[] serializePrivate(NetworkParameters params, boolean bip49) {
return serialize(params, false, bip49);
}
private byte[] serialize(NetworkParameters params, boolean pub) {
private byte[] serialize(NetworkParameters params, boolean pub, boolean bip49) {
ByteBuffer ser = ByteBuffer.allocate(78);
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv());
if(bip49) {
ser.putInt(pub ? params.getBip49HeaderPub() : params.getBip49HeaderPriv());
}
else {
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv());
}
ser.put((byte) getDepth());
ser.putInt(getParentFingerprint());
ser.putInt(getChildNumber().i());
......@@ -482,11 +487,19 @@ public class DeterministicKey extends ECKey {
}
public String serializePubB58(NetworkParameters params) {
return toBase58(serialize(params, true));
return toBase58(serialize(params, true, false));
}
public String serializePrivB58(NetworkParameters params) {
return toBase58(serialize(params, false));
return toBase58(serialize(params, false, false));
}
public String serializePubB58(NetworkParameters params, boolean bip49) {
return toBase58(serialize(params, true, bip49));
}
public String serializePrivB58(NetworkParameters params, boolean bip49) {
return toBase58(serialize(params, false, bip49));
}
static String toBase58(byte[] ser) {
......@@ -521,9 +534,9 @@ public class DeterministicKey extends ECKey {
public static DeterministicKey deserialize(NetworkParameters params, byte[] serializedKey, @Nullable DeterministicKey parent) {
ByteBuffer buffer = ByteBuffer.wrap(serializedKey);
int header = buffer.getInt();
if (header != params.getBip32HeaderPriv() && header != params.getBip32HeaderPub())
if (header != params.getBip32HeaderPriv() && header != params.getBip32HeaderPub() && header != params.getBip49HeaderPriv() && header != params.getBip49HeaderPub())
throw new IllegalArgumentException("Unknown header bytes: " + toBase58(serializedKey).substring(0, 4));
boolean pub = header == params.getBip32HeaderPub();
boolean pub = (header == params.getBip32HeaderPub() || header == params.getBip49HeaderPub());
int depth = buffer.get() & 0xFF; // convert signed byte to positive int since depth cannot be negative
final int parentFingerprint = buffer.getInt();
final int i = buffer.getInt();
......
......@@ -47,6 +47,10 @@ public class MainNetParams extends AbstractBitcoinNetParams {
packetMagic = 0xf9beb4d9L;
bip32HeaderPub = 0x0488B21E; //The 4 byte header that serializes in base58 to "xpub".
bip32HeaderPriv = 0x0488ADE4; //The 4 byte header that serializes in base58 to "xprv"
bip49HeaderPub = 0x049D7CB2; //The 4 byte header that serializes in base58 to "ypub".
bip49HeaderPriv = 0x049D7878; //The 4 byte header that serializes in base58 to "yprv"
bip141HeaderPub = 0x04B24746; //The 4 byte header that serializes in base58 to "zpub".
bip141HeaderPriv = 0x04B2430C; //The 4 byte header that serializes in base58 to "zprv"
majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
......@@ -68,6 +68,10 @@ public class TestNet3Params extends AbstractBitcoinNetParams {
addrSeeds = null;
bip32HeaderPub = 0x043587CF;
bip32HeaderPriv = 0x04358394;
bip49HeaderPub = 0x044A5262;
bip49HeaderPriv = 0x044A4E28;
bip141HeaderPub = 0x045F1CF6;
bip141HeaderPriv = 0x045F18BC;
majorityEnforceBlockUpgrade = TestNet2Params.TESTNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = TestNet2Params.TESTNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
/*
* Copyright by the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
......@@ -92,7 +92,7 @@ import static com.google.common.collect.Lists.newLinkedList;
* keys, you can request 33 keys before more keys will be calculated and the Bloom filter rebuilt and rebroadcast.
* But even when you are requesting the 33rd key, you will still be looking 100 keys ahead.
* </p>
*
*
* @author Andreas Schildbach
*/
@SuppressWarnings("PublicStaticCollectionField")
......@@ -1328,7 +1328,8 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
builder.append("Key birthday: ").append(watchingKey.getCreationTimeSeconds()).append(" [")
.append(Utils.dateTimeFormat(watchingKey.getCreationTimeSeconds() * 1000)).append("]\n");
}
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, false)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, true)).append('\n');
formatAddresses(includePrivateKeys, params, builder);
return builder.toString();
}
......
/*
* Copyright by the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
......@@ -235,9 +235,12 @@ public class MarriedKeyChain extends DeterministicKeyChain {
@Override
protected void formatAddresses(boolean includePrivateKeys, NetworkParameters params, StringBuilder builder2) {
for (DeterministicKeyChain followingChain : followingKeyChains)
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params))
.append('\n');
for (DeterministicKeyChain followingChain : followingKeyChains) {
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, false))
.append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, true))
.append('\n');
}
builder2.append('\n');
for (RedeemData redeemData : marriedKeysRedeemData.values())
formatScript(ScriptBuilder.createP2SHOutputScript(redeemData.redeemScript), builder2, params);
......
......@@ -212,8 +212,8 @@ public class ChildKeyDerivationTest {
{
final String pub58 = key1.serializePubB58(params);
final String priv58 = key1.serializePrivB58(params);
final byte[] pub = key1.serializePublic(params);
final byte[] priv = key1.serializePrivate(params);
final byte[] pub = key1.serializePublic(params, false);
final byte[] priv = key1.serializePrivate(params, false);
assertEquals("xpub661MyMwAqRbcF7mq7Aejj5xZNzFfgi3ABamE9FedDHVmViSzSxYTgAQGcATDo2J821q7Y9EAagjg5EP3L7uBZk11PxZU3hikL59dexfLkz3", pub58);
assertEquals("xprv9s21ZrQH143K2dhN197jMx1ppxRBHFKJpMqdLsF1ewxncv7quRED8N5nksxphju3W7naj1arF56L5PUEWfuSk8h73Sb2uh7bSwyXNrjzhAZ", priv58);
assertArrayEquals(new byte[]{4, -120, -78, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, -68, 93, -104, -97, 31, -105, -18, 109, 112, 104, 45, -77, -77, 18, 85, -29, -120, 86, -113, 26, 48, -18, -79, -110, -6, -27, 87, 86, 24, 124, 99, 3, 96, -33, -14, 67, -19, -47, 16, 76, -49, -11, -30, -123, 7, 56, 101, 91, 74, 125, -127, 61, 42, -103, 90, -93, 66, -36, 2, -126, -107, 30, 24, -111}, pub);
......@@ -230,8 +230,8 @@ public class ChildKeyDerivationTest {
{
final String pub58 = key2.serializePubB58(params);
final String priv58 = key2.serializePrivB58(params);
final byte[] pub = key2.serializePublic(params);
final byte[] priv = key2.serializePrivate(params);
final byte[] pub = key2.serializePublic(params, false);
final byte[] priv = key2.serializePrivate(params, false);
assertEquals(DeterministicKey.deserializeB58(key1, priv58, params), key2);
assertEquals(DeterministicKey.deserializeB58(key1, pub58, params).getPubKeyPoint(), key2.getPubKeyPoint());
assertEquals(DeterministicKey.deserialize(params, priv, key1), key2);
......@@ -247,9 +247,9 @@ public class ChildKeyDerivationTest {
DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.ZERO_HARDENED);
DeterministicKey key4 = HDKeyDerivation.deriveChildKey(key3, ChildNumber.ZERO_HARDENED);
assertEquals(key4.getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params), key3).getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params), null).getPath().size(), 1);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params)).getPath().size(), 1);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false), key3).getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false), null).getPath().size(), 1);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false)).getPath().size(), 1);
}
/** Reserializing a deserialized key should yield the original input */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment