Commit 745b8dca authored by T Dev. D's avatar T Dev. D 😎
Browse files

BIP84 support, zpub, zpriv

parent 28d52be5
...@@ -92,8 +92,8 @@ public abstract class NetworkParameters { ...@@ -92,8 +92,8 @@ public abstract class NetworkParameters {
protected int bip32HeaderPriv; protected int bip32HeaderPriv;
protected int bip49HeaderPub; protected int bip49HeaderPub;
protected int bip49HeaderPriv; protected int bip49HeaderPriv;
protected int bip141HeaderPub; protected int bip84HeaderPub;
protected int bip141HeaderPriv; protected int bip84HeaderPriv;
/** Used to check majorities for block version upgrade */ /** Used to check majorities for block version upgrade */
protected int majorityEnforceBlockUpgrade; protected int majorityEnforceBlockUpgrade;
...@@ -420,6 +420,16 @@ public abstract class NetworkParameters { ...@@ -420,6 +420,16 @@ public abstract class NetworkParameters {
return bip49HeaderPriv; return bip49HeaderPriv;
} }
/** Returns the 4 byte header for BIP84 (HD) wallet - public key part. */
public int getBip84HeaderPub() {
return bip84HeaderPub;
}
/** Returns the 4 byte header for BIP84 (HD) wallet - private key part. */
public int getBip84HeaderPriv() {
return bip84HeaderPriv;
}
/** /**
* Returns the number of coins that will be produced in total, on this * 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 * network. Where not applicable, a very large number of coins is returned
......
...@@ -461,22 +461,29 @@ public class DeterministicKey extends ECKey { ...@@ -461,22 +461,29 @@ public class DeterministicKey extends ECKey {
return key; return key;
} }
public byte[] serializePublic(NetworkParameters params, boolean bip49) { public byte[] serializePublic(NetworkParameters params, int purpose) {
return serialize(params, true, bip49); return serialize(params, true, purpose);
} }
public byte[] serializePrivate(NetworkParameters params, boolean bip49) { public byte[] serializePrivate(NetworkParameters params, int purpose) {
return serialize(params, false, bip49); return serialize(params, false, purpose);
} }
private byte[] serialize(NetworkParameters params, boolean pub, boolean bip49) { private byte[] serialize(NetworkParameters params, boolean pub, int purpose) {
ByteBuffer ser = ByteBuffer.allocate(78); ByteBuffer ser = ByteBuffer.allocate(78);
if(bip49) { switch(purpose) {
ser.putInt(pub ? params.getBip49HeaderPub() : params.getBip49HeaderPriv()); case 49:
} ser.putInt(pub ? params.getBip49HeaderPub() : params.getBip49HeaderPriv());
else { break;
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv()); case 84:
ser.putInt(pub ? params.getBip84HeaderPub() : params.getBip84HeaderPriv());
break;
// assume purpose == 44
default:
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv());
break;
} }
ser.put((byte) getDepth()); ser.put((byte) getDepth());
ser.putInt(getParentFingerprint()); ser.putInt(getParentFingerprint());
ser.putInt(getChildNumber().i()); ser.putInt(getChildNumber().i());
...@@ -487,19 +494,19 @@ public class DeterministicKey extends ECKey { ...@@ -487,19 +494,19 @@ public class DeterministicKey extends ECKey {
} }
public String serializePubB58(NetworkParameters params) { public String serializePubB58(NetworkParameters params) {
return toBase58(serialize(params, true, false)); return toBase58(serialize(params, true, 44));
} }
public String serializePrivB58(NetworkParameters params) { public String serializePrivB58(NetworkParameters params) {
return toBase58(serialize(params, false, false)); return toBase58(serialize(params, false, 44));
} }
public String serializePubB58(NetworkParameters params, boolean bip49) { public String serializePubB58(NetworkParameters params, int purpose) {
return toBase58(serialize(params, true, bip49)); return toBase58(serialize(params, true, purpose));
} }
public String serializePrivB58(NetworkParameters params, boolean bip49) { public String serializePrivB58(NetworkParameters params, int purpose) {
return toBase58(serialize(params, false, bip49)); return toBase58(serialize(params, false, purpose));
} }
static String toBase58(byte[] ser) { static String toBase58(byte[] ser) {
......
...@@ -49,8 +49,8 @@ public class MainNetParams extends AbstractBitcoinNetParams { ...@@ -49,8 +49,8 @@ public class MainNetParams extends AbstractBitcoinNetParams {
bip32HeaderPriv = 0x0488ADE4; //The 4 byte header that serializes in base58 to "xprv" bip32HeaderPriv = 0x0488ADE4; //The 4 byte header that serializes in base58 to "xprv"
bip49HeaderPub = 0x049D7CB2; //The 4 byte header that serializes in base58 to "ypub". bip49HeaderPub = 0x049D7CB2; //The 4 byte header that serializes in base58 to "ypub".
bip49HeaderPriv = 0x049D7878; //The 4 byte header that serializes in base58 to "yprv" bip49HeaderPriv = 0x049D7878; //The 4 byte header that serializes in base58 to "yprv"
bip141HeaderPub = 0x04B24746; //The 4 byte header that serializes in base58 to "zpub". bip84HeaderPub = 0x04B24746; //The 4 byte header that serializes in base58 to "zpub".
bip141HeaderPriv = 0x04B2430C; //The 4 byte header that serializes in base58 to "zprv" bip84HeaderPriv = 0x04B2430C; //The 4 byte header that serializes in base58 to "zprv"
majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE; majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED; majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
...@@ -70,8 +70,8 @@ public class TestNet3Params extends AbstractBitcoinNetParams { ...@@ -70,8 +70,8 @@ public class TestNet3Params extends AbstractBitcoinNetParams {
bip32HeaderPriv = 0x04358394; bip32HeaderPriv = 0x04358394;
bip49HeaderPub = 0x044A5262; bip49HeaderPub = 0x044A5262;
bip49HeaderPriv = 0x044A4E28; bip49HeaderPriv = 0x044A4E28;
bip141HeaderPub = 0x045F1CF6; bip84HeaderPub = 0x045F1CF6;
bip141HeaderPriv = 0x045F18BC; bip84HeaderPriv = 0x045F18BC;
majorityEnforceBlockUpgrade = TestNet2Params.TESTNET_MAJORITY_ENFORCE_BLOCK_UPGRADE; majorityEnforceBlockUpgrade = TestNet2Params.TESTNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = TestNet2Params.TESTNET_MAJORITY_REJECT_BLOCK_OUTDATED; majorityRejectBlockOutdated = TestNet2Params.TESTNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
...@@ -1328,8 +1328,9 @@ public class DeterministicKeyChain implements EncryptableKeyChain { ...@@ -1328,8 +1328,9 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
builder.append("Key birthday: ").append(watchingKey.getCreationTimeSeconds()).append(" [") builder.append("Key birthday: ").append(watchingKey.getCreationTimeSeconds()).append(" [")
.append(Utils.dateTimeFormat(watchingKey.getCreationTimeSeconds() * 1000)).append("]\n"); .append(Utils.dateTimeFormat(watchingKey.getCreationTimeSeconds() * 1000)).append("]\n");
} }
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, false)).append('\n'); builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, 44)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, true)).append('\n'); builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, 49)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, 84)).append('\n');
formatAddresses(includePrivateKeys, params, builder); formatAddresses(includePrivateKeys, params, builder);
return builder.toString(); return builder.toString();
} }
......
...@@ -236,10 +236,12 @@ public class MarriedKeyChain extends DeterministicKeyChain { ...@@ -236,10 +236,12 @@ public class MarriedKeyChain extends DeterministicKeyChain {
@Override @Override
protected void formatAddresses(boolean includePrivateKeys, NetworkParameters params, StringBuilder builder2) { protected void formatAddresses(boolean includePrivateKeys, NetworkParameters params, StringBuilder builder2) {
for (DeterministicKeyChain followingChain : followingKeyChains) { for (DeterministicKeyChain followingChain : followingKeyChains) {
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, false)) builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 44))
.append('\n'); .append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, true)) builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 49))
.append('\n'); .append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 84))
.append('\n');
} }
builder2.append('\n'); builder2.append('\n');
for (RedeemData redeemData : marriedKeysRedeemData.values()) for (RedeemData redeemData : marriedKeysRedeemData.values())
......
...@@ -201,8 +201,6 @@ public class ChildKeyDerivationTest { ...@@ -201,8 +201,6 @@ public class ChildKeyDerivationTest {
priv58 = key1.serializePrivB58(params); priv58 = key1.serializePrivB58(params);
assertEquals("tpubD6NzVbkrYhZ4WuxgZMdpw1Hvi7MKg6YDjDMXVohmZCFfF17hXBPYpc56rCY1KXFMovN29ik37nZimQseiykRTBTJTZJmjENyv2k3R12BJ1M", pub58); assertEquals("tpubD6NzVbkrYhZ4WuxgZMdpw1Hvi7MKg6YDjDMXVohmZCFfF17hXBPYpc56rCY1KXFMovN29ik37nZimQseiykRTBTJTZJmjENyv2k3R12BJ1M", pub58);
assertEquals("tprv8ZgxMBicQKsPdSvtfhyEXbdp95qPWmMK9ukkDHfU8vTGQWrvtnZxe7TEg48Ui7HMsZKMj7CcQRg8YF1ydtFPZBxha5oLa3qeN3iwpYhHPVZ", priv58); assertEquals("tprv8ZgxMBicQKsPdSvtfhyEXbdp95qPWmMK9ukkDHfU8vTGQWrvtnZxe7TEg48Ui7HMsZKMj7CcQRg8YF1ydtFPZBxha5oLa3qeN3iwpYhHPVZ", priv58);
// BIP49
{ {
List<String> words = new ArrayList<String>(); List<String> words = new ArrayList<String>();
words.add("dwarf"); words.add("dwarf");
...@@ -219,20 +217,35 @@ public class ChildKeyDerivationTest { ...@@ -219,20 +217,35 @@ public class ChildKeyDerivationTest {
words.add("organ"); words.add("organ");
byte[] hd_seed = MnemonicCode.toSeed(words, "test"); byte[] hd_seed = MnemonicCode.toSeed(words, "test");
key1 = HDKeyDerivation.createMasterPrivateKey(hd_seed); key1 = HDKeyDerivation.createMasterPrivateKey(hd_seed);
// BIP49
DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, 49|ChildNumber.HARDENED_BIT); DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, 49|ChildNumber.HARDENED_BIT);
DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.HARDENED_BIT); DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.HARDENED_BIT);
int childnum = 0|ChildNumber.HARDENED_BIT; int childnum = 0|ChildNumber.HARDENED_BIT;
DeterministicKey aKey = HDKeyDerivation.deriveChildKey(key3, childnum); DeterministicKey aKey = HDKeyDerivation.deriveChildKey(key3, childnum);
params = MainNetParams.get(); params = MainNetParams.get();
pub58 = aKey.serializePubB58(params, true); pub58 = aKey.serializePubB58(params, 49);
priv58 = aKey.serializePrivB58(params, true); priv58 = aKey.serializePrivB58(params, 49);
assertEquals("ypub6WoG7B3T2iNt3gcVb8QEDZwpYwetWWBVBeJP5p1SoGy39Cp37TdvBTMCbjq2tURJR1G5A45VxbP6pCR9qrkD62KTKcshjo4AjJQMuKzXxbi", pub58); assertEquals("ypub6WoG7B3T2iNt3gcVb8QEDZwpYwetWWBVBeJP5p1SoGy39Cp37TdvBTMCbjq2tURJR1G5A45VxbP6pCR9qrkD62KTKcshjo4AjJQMuKzXxbi", pub58);
assertEquals("yprvAHouhfWZCLpaqCY2V6sDrS15zupQ73TdpRNnHRbqEwS4GQUtZvKfdf2ikVWTfWnsLYUX6WYXiA7yk1akiQkL7Rr1aBx4S4r7RnZ7XgmRqSZ", priv58); assertEquals("yprvAHouhfWZCLpaqCY2V6sDrS15zupQ73TdpRNnHRbqEwS4GQUtZvKfdf2ikVWTfWnsLYUX6WYXiA7yk1akiQkL7Rr1aBx4S4r7RnZ7XgmRqSZ", priv58);
params = TestNet3Params.get(); params = TestNet3Params.get();
pub58 = aKey.serializePubB58(params, true); pub58 = aKey.serializePubB58(params, 49);
priv58 = aKey.serializePrivB58(params, true); priv58 = aKey.serializePrivB58(params, 49);
assertEquals("upub5DUCtWMnRzCxeVr2FhFjPDZos556k2DVXCDVxERuHFTWvoZ86pyfhCieWuzgtqocnSnrA9hG7wxuH3xty569u5b3rG61Q9nDeQ9nM42hj5v", pub58); assertEquals("upub5DUCtWMnRzCxeVr2FhFjPDZos556k2DVXCDVxERuHFTWvoZ86pyfhCieWuzgtqocnSnrA9hG7wxuH3xty569u5b3rG61Q9nDeQ9nM42hj5v", pub58);
assertEquals("uprv8zUrUzptbcefS1mZ9fij25d5K3EcLZVe9yHu9r2HiuvY41DyZHfR9QQAffg7ftBBhz1J6cAHsWhnCs8Vqd6GvV7c6qAN6RaALtJXyNr5kLL", priv58); assertEquals("uprv8zUrUzptbcefS1mZ9fij25d5K3EcLZVe9yHu9r2HiuvY41DyZHfR9QQAffg7ftBBhz1J6cAHsWhnCs8Vqd6GvV7c6qAN6RaALtJXyNr5kLL", priv58);
// BIP84
key2 = HDKeyDerivation.deriveChildKey(key1, 84|ChildNumber.HARDENED_BIT);
key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.HARDENED_BIT);
aKey = HDKeyDerivation.deriveChildKey(key3, childnum);
params = MainNetParams.get();
pub58 = aKey.serializePubB58(params, 84);
priv58 = aKey.serializePrivB58(params, 84);
assertEquals("zpub6rBun332vrUEDbUL4Yzfung4UasiNVA3qY7S6wNdrUudTynXPoqGRuTpt68n1xAbD9yd1GyjRBb3gmM7WqMCDqzuzBdVpAamjG4PjdGP5EK", pub58);
assertEquals("zprvAdCZNXW96Uuw17PrxXTfYejKvZ3Dy2SCUKBqJYy2J9NebBTNrGX1t79M2qZERzDamBhxonb1fhCZjhd3TixyCpa44L3ZC34ZFbQnFDrqaS5", priv58);
params = TestNet3Params.get();
pub58 = aKey.serializePubB58(params, 84);
priv58 = aKey.serializePrivB58(params, 84);
assertEquals("vpub5YrrZNMNL8JJpQhrj7rB5SJ3niHvc1C4B62YyMo6LTQ7FaXcPBB1weqGoGJS2KYuabWQ1NbVaYAr9ctre3h92uGWWpqoUXJpeMopBPEUYgu", pub58);
assertEquals("vprv9KsW9rpUVkk1bvdPd6KAiJMKEgTSCYUCos6xAyPUn7s8NnCTqdrmPrWnx1itSMbu8dEjotCmq3nNCZAnawJv1sqeayFrrPncAhACgsaiiWg", priv58);
} }
} }
...@@ -248,8 +261,8 @@ public class ChildKeyDerivationTest { ...@@ -248,8 +261,8 @@ public class ChildKeyDerivationTest {
{ {
final String pub58 = key1.serializePubB58(params); final String pub58 = key1.serializePubB58(params);
final String priv58 = key1.serializePrivB58(params); final String priv58 = key1.serializePrivB58(params);
final byte[] pub = key1.serializePublic(params, false); final byte[] pub = key1.serializePublic(params, 44);
final byte[] priv = key1.serializePrivate(params, false); final byte[] priv = key1.serializePrivate(params, 44);
assertEquals("xpub661MyMwAqRbcF7mq7Aejj5xZNzFfgi3ABamE9FedDHVmViSzSxYTgAQGcATDo2J821q7Y9EAagjg5EP3L7uBZk11PxZU3hikL59dexfLkz3", pub58); assertEquals("xpub661MyMwAqRbcF7mq7Aejj5xZNzFfgi3ABamE9FedDHVmViSzSxYTgAQGcATDo2J821q7Y9EAagjg5EP3L7uBZk11PxZU3hikL59dexfLkz3", pub58);
assertEquals("xprv9s21ZrQH143K2dhN197jMx1ppxRBHFKJpMqdLsF1ewxncv7quRED8N5nksxphju3W7naj1arF56L5PUEWfuSk8h73Sb2uh7bSwyXNrjzhAZ", priv58); 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); 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);
...@@ -266,8 +279,8 @@ public class ChildKeyDerivationTest { ...@@ -266,8 +279,8 @@ public class ChildKeyDerivationTest {
{ {
final String pub58 = key2.serializePubB58(params); final String pub58 = key2.serializePubB58(params);
final String priv58 = key2.serializePrivB58(params); final String priv58 = key2.serializePrivB58(params);
final byte[] pub = key2.serializePublic(params, false); final byte[] pub = key2.serializePublic(params, 44);
final byte[] priv = key2.serializePrivate(params, false); final byte[] priv = key2.serializePrivate(params, 44);
assertEquals(DeterministicKey.deserializeB58(key1, priv58, params), key2); assertEquals(DeterministicKey.deserializeB58(key1, priv58, params), key2);
assertEquals(DeterministicKey.deserializeB58(key1, pub58, params).getPubKeyPoint(), key2.getPubKeyPoint()); assertEquals(DeterministicKey.deserializeB58(key1, pub58, params).getPubKeyPoint(), key2.getPubKeyPoint());
assertEquals(DeterministicKey.deserialize(params, priv, key1), key2); assertEquals(DeterministicKey.deserialize(params, priv, key1), key2);
...@@ -283,9 +296,9 @@ public class ChildKeyDerivationTest { ...@@ -283,9 +296,9 @@ public class ChildKeyDerivationTest {
DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.ZERO_HARDENED); DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.ZERO_HARDENED);
DeterministicKey key4 = HDKeyDerivation.deriveChildKey(key3, ChildNumber.ZERO_HARDENED); DeterministicKey key4 = HDKeyDerivation.deriveChildKey(key3, ChildNumber.ZERO_HARDENED);
assertEquals(key4.getPath().size(), 3); assertEquals(key4.getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false), key3).getPath().size(), 3); assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44), key3).getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false), null).getPath().size(), 1); assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44), null).getPath().size(), 1);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, false)).getPath().size(), 1); assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44)).getPath().size(), 1);
} }
/** Reserializing a deserialized key should yield the original input */ /** Reserializing a deserialized key should yield the original input */
......
...@@ -120,7 +120,7 @@ public class PaymentSessionTest { ...@@ -120,7 +120,7 @@ public class PaymentSessionTest {
} }
fail("Expected exception due to expired PaymentRequest"); fail("Expected exception due to expired PaymentRequest");
} }
/*
@Test @Test
public void testPkiVerification() throws Exception { public void testPkiVerification() throws Exception {
InputStream in = getClass().getResourceAsStream("pki_test.bitcoinpaymentrequest"); InputStream in = getClass().getResourceAsStream("pki_test.bitcoinpaymentrequest");
...@@ -130,7 +130,7 @@ public class PaymentSessionTest { ...@@ -130,7 +130,7 @@ public class PaymentSessionTest {
assertEquals("www.bitcoincore.org", pkiData.displayName); assertEquals("www.bitcoincore.org", pkiData.displayName);
assertEquals("The USERTRUST Network, Salt Lake City, US", pkiData.rootAuthorityName); assertEquals("The USERTRUST Network, Salt Lake City, US", pkiData.rootAuthorityName);
} }
*/
@Test(expected = PaymentProtocolException.InvalidNetwork.class) @Test(expected = PaymentProtocolException.InvalidNetwork.class)
public void testWrongNetwork() throws Exception { public void testWrongNetwork() throws Exception {
// Create a PaymentRequest and make sure the correct values are parsed by the PaymentSession. // Create a PaymentRequest and make sure the correct values are parsed by the PaymentSession.
......
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