refactor to parametrize with keypurpose

This commit is contained in:
Craig Raw 2020-05-23 18:10:04 +02:00
parent de70f44535
commit c871bf829a
4 changed files with 44 additions and 35 deletions

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.drongo;
public enum KeyPurpose {
RECEIVE(0), CHANGE(1);
private final int pathIndex;
KeyPurpose(int pathIndex) {
this.pathIndex = pathIndex;
}
public int getPathIndex() {
return pathIndex;
}
}

View file

@ -2,6 +2,7 @@ package com.sparrowwallet.drongo.wallet;
import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation; import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.crypto.*; import com.sparrowwallet.drongo.crypto.*;
@ -103,22 +104,13 @@ public class Keystore {
return new ExtendedKey(derivedKey, derivedKey.getParentFingerprint(), derivation.get(derivation.size() - 1)); return new ExtendedKey(derivedKey, derivedKey.getParentFingerprint(), derivation.get(derivation.size() - 1));
} }
public DeterministicKey getReceivingKey(int keyIndex) { public DeterministicKey getKey(KeyPurpose keyPurpose, int keyIndex) {
List<ChildNumber> receivingDerivation = List.of(extendedPublicKey.getKeyChildNumber(), new ChildNumber(0), new ChildNumber(keyIndex)); List<ChildNumber> receivingDerivation = List.of(extendedPublicKey.getKeyChildNumber(), new ChildNumber(keyPurpose.getPathIndex()), new ChildNumber(keyIndex));
return extendedPublicKey.getKey(receivingDerivation); return extendedPublicKey.getKey(receivingDerivation);
} }
public KeyDerivation getReceivingDerivation(int keyIndex) { public KeyDerivation getDerivation(KeyPurpose keyPurpose, int keyIndex) {
return getKeyDerivation().extend(new ChildNumber(0)).extend(new ChildNumber(keyIndex)); return getKeyDerivation().extend(new ChildNumber(keyPurpose.getPathIndex())).extend(new ChildNumber(keyIndex));
}
public DeterministicKey getChangeKey(int keyIndex) {
List<ChildNumber> receivingDerivation = List.of(extendedPublicKey.getKeyChildNumber(), new ChildNumber(1), new ChildNumber(keyIndex));
return extendedPublicKey.getKey(receivingDerivation);
}
public KeyDerivation getChangeDerivation(int keyIndex) {
return getKeyDerivation().extend(new ChildNumber(1)).extend(new ChildNumber(keyIndex));
} }
public boolean isValid() { public boolean isValid() {

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.wallet; package com.sparrowwallet.drongo.wallet;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.Address;
import com.sparrowwallet.drongo.crypto.DeterministicKey; import com.sparrowwallet.drongo.crypto.DeterministicKey;
import com.sparrowwallet.drongo.crypto.ECKey; import com.sparrowwallet.drongo.crypto.ECKey;
@ -75,31 +76,31 @@ public class Wallet {
this.keystores = keystores; this.keystores = keystores;
} }
public Address getReceivingAddress(int index) { public Address getAddress(KeyPurpose keyPurpose, int index) {
if(policyType == PolicyType.SINGLE) { if(policyType == PolicyType.SINGLE) {
Keystore keystore = getKeystores().get(0); Keystore keystore = getKeystores().get(0);
DeterministicKey key = keystore.getReceivingKey(index); DeterministicKey key = keystore.getKey(keyPurpose, index);
return scriptType.getAddress(key); return scriptType.getAddress(key);
} else if(policyType == PolicyType.MULTI) { } else if(policyType == PolicyType.MULTI) {
List<ECKey> pubKeys = getKeystores().stream().map(keystore -> keystore.getReceivingKey(index)).collect(Collectors.toList()); List<ECKey> pubKeys = getKeystores().stream().map(keystore -> keystore.getKey(keyPurpose, index)).collect(Collectors.toList());
Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys); Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys);
return scriptType.getAddress(script); return scriptType.getAddress(script);
} else { } else {
throw new UnsupportedOperationException("Cannot determine receiving addresses for custom policies"); throw new UnsupportedOperationException("Cannot determine addresses for custom policies");
} }
} }
public Address getChangeAddress(int index) { public Script getOutputScript(KeyPurpose keyPurpose, int index) {
if(policyType == PolicyType.SINGLE) { if(policyType == PolicyType.SINGLE) {
Keystore keystore = getKeystores().get(0); Keystore keystore = getKeystores().get(0);
DeterministicKey key = keystore.getChangeKey(index); DeterministicKey key = keystore.getKey(keyPurpose, index);
return scriptType.getAddress(key); return scriptType.getOutputScript(key);
} else if(policyType == PolicyType.MULTI) { } else if(policyType == PolicyType.MULTI) {
List<ECKey> pubKeys = getKeystores().stream().map(keystore -> keystore.getChangeKey(index)).collect(Collectors.toList()); List<ECKey> pubKeys = getKeystores().stream().map(keystore -> keystore.getKey(keyPurpose, index)).collect(Collectors.toList());
Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys); Script script = ScriptType.MULTISIG.getOutputScript(defaultPolicy.getNumSignaturesRequired(), pubKeys);
return scriptType.getAddress(script); return scriptType.getOutputScript(script);
} else { } else {
throw new UnsupportedOperationException("Cannot determine change addresses for custom policies"); throw new UnsupportedOperationException("Cannot determine output script for custom policies");
} }
} }

View file

@ -1,5 +1,6 @@
package com.sparrowwallet.drongo.wallet; package com.sparrowwallet.drongo.wallet;
import com.sparrowwallet.drongo.KeyPurpose;
import com.sparrowwallet.drongo.crypto.Argon2KeyDeriver; import com.sparrowwallet.drongo.crypto.Argon2KeyDeriver;
import com.sparrowwallet.drongo.crypto.Key; import com.sparrowwallet.drongo.crypto.Key;
import com.sparrowwallet.drongo.crypto.KeyDeriver; import com.sparrowwallet.drongo.crypto.KeyDeriver;
@ -78,8 +79,8 @@ public class WalletTest {
wallet.getKeystores().add(keystore); wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, wallet.getKeystores(), 1)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2PKH, wallet.getKeystores(), 1));
Assert.assertEquals("12kTQjuWDp7Uu6PwY6CsS1KLTt3d1DBHZa", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("12kTQjuWDp7Uu6PwY6CsS1KLTt3d1DBHZa", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("1HbQwQCitHQxVtP39isXmUdHx7hQCZovrK", wallet.getReceivingAddress(1).toString()); Assert.assertEquals("1HbQwQCitHQxVtP39isXmUdHx7hQCZovrK", wallet.getAddress(KeyPurpose.RECEIVE, 1).toString());
} }
@Test @Test
@ -93,8 +94,8 @@ public class WalletTest {
wallet.getKeystores().add(keystore); wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2SH_P2WPKH, wallet.getKeystores(), 1)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2SH_P2WPKH, wallet.getKeystores(), 1));
Assert.assertEquals("3NZLE4TntsjtcZ5MbrfxwtYo9meBVybVQj", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("3NZLE4TntsjtcZ5MbrfxwtYo9meBVybVQj", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("32YBBuRsp8XTeLx4T6BmD2L4nANGaNDkSg", wallet.getReceivingAddress(1).toString()); Assert.assertEquals("32YBBuRsp8XTeLx4T6BmD2L4nANGaNDkSg", wallet.getAddress(KeyPurpose.RECEIVE, 1).toString());
} }
@Test @Test
@ -108,8 +109,8 @@ public class WalletTest {
wallet.getKeystores().add(keystore); wallet.getKeystores().add(keystore);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), 1)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.SINGLE, ScriptType.P2WPKH, wallet.getKeystores(), 1));
Assert.assertEquals("bc1quvxdut936uswuxwxrk6nvjmgwxh463r0fjwn55", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("bc1quvxdut936uswuxwxrk6nvjmgwxh463r0fjwn55", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("bc1q95j2862dz7mqpraw6qdjc70gumyu5z7adgq9x9", wallet.getReceivingAddress(1).toString()); Assert.assertEquals("bc1q95j2862dz7mqpraw6qdjc70gumyu5z7adgq9x9", wallet.getAddress(KeyPurpose.RECEIVE, 1).toString());
} }
@Test @Test
@ -133,8 +134,8 @@ public class WalletTest {
wallet.getKeystores().add(keystore2); wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH, wallet.getKeystores(), 2)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH, wallet.getKeystores(), 2));
Assert.assertEquals("38kq6yz4VcYymTExQPY3gppbz38mtPLveK", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("38kq6yz4VcYymTExQPY3gppbz38mtPLveK", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("3EdKaNsnjBTBggWcSMRyVju6GbHWy68mAH", wallet.getChangeAddress(1).toString()); Assert.assertEquals("3EdKaNsnjBTBggWcSMRyVju6GbHWy68mAH", wallet.getAddress(KeyPurpose.CHANGE, 1).toString());
} }
@Test @Test
@ -158,8 +159,8 @@ public class WalletTest {
wallet.getKeystores().add(keystore2); wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH_P2WSH, wallet.getKeystores(), 2)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2SH_P2WSH, wallet.getKeystores(), 2));
Assert.assertEquals("3Mw8xqAHh8g3eBvh7q1UEUmoexqdXDK9Tf", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("3Mw8xqAHh8g3eBvh7q1UEUmoexqdXDK9Tf", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("35dFo1ivJ8jyHpyf42MWvnYf5LBU8Siren", wallet.getChangeAddress(1).toString()); Assert.assertEquals("35dFo1ivJ8jyHpyf42MWvnYf5LBU8Siren", wallet.getAddress(KeyPurpose.CHANGE, 1).toString());
} }
@Test @Test
@ -183,7 +184,7 @@ public class WalletTest {
wallet.getKeystores().add(keystore2); wallet.getKeystores().add(keystore2);
wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2WSH, wallet.getKeystores(), 2)); wallet.setDefaultPolicy(Policy.getPolicy(PolicyType.MULTI, ScriptType.P2WSH, wallet.getKeystores(), 2));
Assert.assertEquals("bc1q20e4vm656h5lvmngz9ztz6hjzftvh39yzngqhuqzk8qzj7tqnzaqgclrwc", wallet.getReceivingAddress(0).toString()); Assert.assertEquals("bc1q20e4vm656h5lvmngz9ztz6hjzftvh39yzngqhuqzk8qzj7tqnzaqgclrwc", wallet.getAddress(KeyPurpose.RECEIVE, 0).toString());
Assert.assertEquals("bc1q2epdx7dplwaas2jucfrzmxm8350rqh68hs6vqreysku80ye44mfqla85f2", wallet.getChangeAddress(1).toString()); Assert.assertEquals("bc1q2epdx7dplwaas2jucfrzmxm8350rqh68hs6vqreysku80ye44mfqla85f2", wallet.getAddress(KeyPurpose.CHANGE, 1).toString());
} }
} }