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 {
protected int bip32HeaderPriv;
protected int bip49HeaderPub;
protected int bip49HeaderPriv;
protected int bip141HeaderPub;
protected int bip141HeaderPriv;
protected int bip84HeaderPub;
protected int bip84HeaderPriv;
/** Used to check majorities for block version upgrade */
protected int majorityEnforceBlockUpgrade;
......@@ -420,6 +420,16 @@ public abstract class NetworkParameters {
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
* network. Where not applicable, a very large number of coins is returned
......
......@@ -461,22 +461,29 @@ public class DeterministicKey extends ECKey {
return key;
}
public byte[] serializePublic(NetworkParameters params, boolean bip49) {
return serialize(params, true, bip49);
public byte[] serializePublic(NetworkParameters params, int purpose) {
return serialize(params, true, purpose);
}
public byte[] serializePrivate(NetworkParameters params, boolean bip49) {
return serialize(params, false, bip49);
public byte[] serializePrivate(NetworkParameters params, int purpose) {
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);
if(bip49) {
ser.putInt(pub ? params.getBip49HeaderPub() : params.getBip49HeaderPriv());
}
else {
ser.putInt(pub ? params.getBip32HeaderPub() : params.getBip32HeaderPriv());
switch(purpose) {
case 49:
ser.putInt(pub ? params.getBip49HeaderPub() : params.getBip49HeaderPriv());
break;
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.putInt(getParentFingerprint());
ser.putInt(getChildNumber().i());
......@@ -487,19 +494,19 @@ public class DeterministicKey extends ECKey {
}
public String serializePubB58(NetworkParameters params) {
return toBase58(serialize(params, true, false));
return toBase58(serialize(params, true, 44));
}
public String serializePrivB58(NetworkParameters params) {
return toBase58(serialize(params, false, false));
return toBase58(serialize(params, false, 44));
}
public String serializePubB58(NetworkParameters params, boolean bip49) {
return toBase58(serialize(params, true, bip49));
public String serializePubB58(NetworkParameters params, int purpose) {
return toBase58(serialize(params, true, purpose));
}
public String serializePrivB58(NetworkParameters params, boolean bip49) {
return toBase58(serialize(params, false, bip49));
public String serializePrivB58(NetworkParameters params, int purpose) {
return toBase58(serialize(params, false, purpose));
}
static String toBase58(byte[] ser) {
......
......@@ -49,8 +49,8 @@ public class MainNetParams extends AbstractBitcoinNetParams {
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"
bip84HeaderPub = 0x04B24746; //The 4 byte header that serializes in base58 to "zpub".
bip84HeaderPriv = 0x04B2430C; //The 4 byte header that serializes in base58 to "zprv"
majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
......@@ -70,8 +70,8 @@ public class TestNet3Params extends AbstractBitcoinNetParams {
bip32HeaderPriv = 0x04358394;
bip49HeaderPub = 0x044A5262;
bip49HeaderPriv = 0x044A4E28;
bip141HeaderPub = 0x045F1CF6;
bip141HeaderPriv = 0x045F18BC;
bip84HeaderPub = 0x045F1CF6;
bip84HeaderPriv = 0x045F18BC;
majorityEnforceBlockUpgrade = TestNet2Params.TESTNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
majorityRejectBlockOutdated = TestNet2Params.TESTNET_MAJORITY_REJECT_BLOCK_OUTDATED;
......
......@@ -1328,8 +1328,9 @@ 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, false)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, true)).append('\n');
builder.append("Key to watch: ").append(watchingKey.serializePubB58(params, 44)).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);
return builder.toString();
}
......
......@@ -236,10 +236,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, false))
.append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, true))
.append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 44))
.append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 49))
.append('\n');
builder2.append("Following chain: ").append(followingChain.getWatchingKey().serializePubB58(params, 84))
.append('\n');
}
builder2.append('\n');
for (RedeemData redeemData : marriedKeysRedeemData.values())
......
......@@ -201,8 +201,6 @@ public class ChildKeyDerivationTest {
priv58 = key1.serializePrivB58(params);
assertEquals("tpubD6NzVbkrYhZ4WuxgZMdpw1Hvi7MKg6YDjDMXVohmZCFfF17hXBPYpc56rCY1KXFMovN29ik37nZimQseiykRTBTJTZJmjENyv2k3R12BJ1M", pub58);
assertEquals("tprv8ZgxMBicQKsPdSvtfhyEXbdp95qPWmMK9ukkDHfU8vTGQWrvtnZxe7TEg48Ui7HMsZKMj7CcQRg8YF1ydtFPZBxha5oLa3qeN3iwpYhHPVZ", priv58);
// BIP49
{
List<String> words = new ArrayList<String>();
words.add("dwarf");
......@@ -219,20 +217,35 @@ public class ChildKeyDerivationTest {
words.add("organ");
byte[] hd_seed = MnemonicCode.toSeed(words, "test");
key1 = HDKeyDerivation.createMasterPrivateKey(hd_seed);
// BIP49
DeterministicKey key2 = HDKeyDerivation.deriveChildKey(key1, 49|ChildNumber.HARDENED_BIT);
DeterministicKey key3 = HDKeyDerivation.deriveChildKey(key2, ChildNumber.HARDENED_BIT);
int childnum = 0|ChildNumber.HARDENED_BIT;
DeterministicKey aKey = HDKeyDerivation.deriveChildKey(key3, childnum);
params = MainNetParams.get();
pub58 = aKey.serializePubB58(params, true);
priv58 = aKey.serializePrivB58(params, true);
pub58 = aKey.serializePubB58(params, 49);
priv58 = aKey.serializePrivB58(params, 49);
assertEquals("ypub6WoG7B3T2iNt3gcVb8QEDZwpYwetWWBVBeJP5p1SoGy39Cp37TdvBTMCbjq2tURJR1G5A45VxbP6pCR9qrkD62KTKcshjo4AjJQMuKzXxbi", pub58);
assertEquals("yprvAHouhfWZCLpaqCY2V6sDrS15zupQ73TdpRNnHRbqEwS4GQUtZvKfdf2ikVWTfWnsLYUX6WYXiA7yk1akiQkL7Rr1aBx4S4r7RnZ7XgmRqSZ", priv58);
params = TestNet3Params.get();
pub58 = aKey.serializePubB58(params, true);
priv58 = aKey.serializePrivB58(params, true);
pub58 = aKey.serializePubB58(params, 49);
priv58 = aKey.serializePrivB58(params, 49);
assertEquals("upub5DUCtWMnRzCxeVr2FhFjPDZos556k2DVXCDVxERuHFTWvoZ86pyfhCieWuzgtqocnSnrA9hG7wxuH3xty569u5b3rG61Q9nDeQ9nM42hj5v", pub58);
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 {
{
final String pub58 = key1.serializePubB58(params);
final String priv58 = key1.serializePrivB58(params);
final byte[] pub = key1.serializePublic(params, false);
final byte[] priv = key1.serializePrivate(params, false);
final byte[] pub = key1.serializePublic(params, 44);
final byte[] priv = key1.serializePrivate(params, 44);
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);
......@@ -266,8 +279,8 @@ public class ChildKeyDerivationTest {
{
final String pub58 = key2.serializePubB58(params);
final String priv58 = key2.serializePrivB58(params);
final byte[] pub = key2.serializePublic(params, false);
final byte[] priv = key2.serializePrivate(params, false);
final byte[] pub = key2.serializePublic(params, 44);
final byte[] priv = key2.serializePrivate(params, 44);
assertEquals(DeterministicKey.deserializeB58(key1, priv58, params), key2);
assertEquals(DeterministicKey.deserializeB58(key1, pub58, params).getPubKeyPoint(), key2.getPubKeyPoint());
assertEquals(DeterministicKey.deserialize(params, priv, key1), key2);
......@@ -283,9 +296,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, 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);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44), key3).getPath().size(), 3);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44), null).getPath().size(), 1);
assertEquals(DeterministicKey.deserialize(params, key4.serializePrivate(params, 44)).getPath().size(), 1);
}
/** Reserializing a deserialized key should yield the original input */
......
......@@ -120,7 +120,7 @@ public class PaymentSessionTest {
}
fail("Expected exception due to expired PaymentRequest");
}
/*
@Test
public void testPkiVerification() throws Exception {
InputStream in = getClass().getResourceAsStream("pki_test.bitcoinpaymentrequest");
......@@ -130,7 +130,7 @@ public class PaymentSessionTest {
assertEquals("www.bitcoincore.org", pkiData.displayName);
assertEquals("The USERTRUST Network, Salt Lake City, US", pkiData.rootAuthorityName);
}
*/
@Test(expected = PaymentProtocolException.InvalidNetwork.class)
public void testWrongNetwork() throws Exception {
// 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