address and related optimizations

This commit is contained in:
Craig Raw 2022-07-15 13:42:27 +02:00
parent fefebbabb5
commit 9ae1f68dc4
11 changed files with 48 additions and 50 deletions

View file

@ -9,14 +9,14 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
import java.util.Arrays; import java.util.Arrays;
public abstract class Address { public abstract class Address {
protected final byte[] hash; protected final byte[] data;
public Address(byte[] hash) { public Address(byte[] data) {
this.hash = hash; this.data = data;
} }
public byte[] getHash() { public byte[] getData() {
return hash; return data;
} }
public String getAddress() { public String getAddress() {
@ -24,7 +24,7 @@ public abstract class Address {
} }
public String getAddress(Network network) { public String getAddress(Network network) {
return Base58.encodeChecked(getVersion(network), hash); return Base58.encodeChecked(getVersion(network), data);
} }
public String toString() { public String toString() {
@ -50,16 +50,15 @@ public abstract class Address {
public abstract String getOutputScriptDataType(); public abstract String getOutputScriptDataType();
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(!(obj instanceof Address)) { if(!(obj instanceof Address address)) {
return false; return false;
} }
Address address = (Address)obj; return Arrays.equals(data, address.data) && getVersion(Network.get()) == address.getVersion(Network.get());
return address.getAddress().equals(this.getAddress());
} }
public int hashCode() { public int hashCode() {
return getAddress().hashCode(); return Arrays.hashCode(data) + getVersion(Network.get());
} }
public static Address fromString(String address) throws InvalidAddressException { public static Address fromString(String address) throws InvalidAddressException {

View file

@ -6,11 +6,8 @@ import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
public class P2PKAddress extends Address { public class P2PKAddress extends Address {
private final byte[] pubKey;
public P2PKAddress(byte[] pubKey) { public P2PKAddress(byte[] pubKey) {
super(Utils.sha256hash160(pubKey)); super(pubKey);
this.pubKey = pubKey;
} }
@Override @Override
@ -18,17 +15,22 @@ public class P2PKAddress extends Address {
return network.getP2PKHAddressHeader(); return network.getP2PKHAddressHeader();
} }
@Override
public String getAddress(Network network) {
return Utils.bytesToHex(data);
}
public ScriptType getScriptType() { public ScriptType getScriptType() {
return ScriptType.P2PK; return ScriptType.P2PK;
} }
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(pubKey); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return pubKey; return data;
} }
@Override @Override

View file

@ -21,12 +21,12 @@ public class P2PKHAddress extends Address {
@Override @Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(hash); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return hash; return data;
} }
@Override @Override

View file

@ -22,12 +22,12 @@ public class P2SHAddress extends Address {
@Override @Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(hash); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return hash; return data;
} }
@Override @Override

View file

@ -1,17 +1,13 @@
package com.sparrowwallet.drongo.address; package com.sparrowwallet.drongo.address;
import com.sparrowwallet.drongo.Network; import com.sparrowwallet.drongo.Network;
import com.sparrowwallet.drongo.Utils;
import com.sparrowwallet.drongo.protocol.Bech32; import com.sparrowwallet.drongo.protocol.Bech32;
import com.sparrowwallet.drongo.protocol.Script; import com.sparrowwallet.drongo.protocol.Script;
import com.sparrowwallet.drongo.protocol.ScriptType; import com.sparrowwallet.drongo.protocol.ScriptType;
public class P2TRAddress extends Address { public class P2TRAddress extends Address {
private final byte[] pubKey;
public P2TRAddress(byte[] pubKey) { public P2TRAddress(byte[] pubKey) {
super(Utils.sha256hash160(pubKey)); super(pubKey);
this.pubKey = pubKey;
} }
@Override @Override
@ -21,7 +17,7 @@ public class P2TRAddress extends Address {
@Override @Override
public String getAddress(Network network) { public String getAddress(Network network) {
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), pubKey); return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
} }
@Override @Override
@ -31,12 +27,12 @@ public class P2TRAddress extends Address {
@Override @Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(pubKey); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return pubKey; return data;
} }
@Override @Override

View file

@ -17,7 +17,7 @@ public class P2WPKHAddress extends Address {
@Override @Override
public String getAddress(Network network) { public String getAddress(Network network) {
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash); return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
} }
@Override @Override
@ -27,12 +27,12 @@ public class P2WPKHAddress extends Address {
@Override @Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(hash); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return hash; return data;
} }
@Override @Override

View file

@ -15,7 +15,7 @@ public class P2WSHAddress extends Address {
@Override @Override
public String getAddress(Network network) { public String getAddress(Network network) {
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash); return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
} }
@Override @Override
@ -25,12 +25,12 @@ public class P2WSHAddress extends Address {
@Override @Override
public Script getOutputScript() { public Script getOutputScript() {
return getScriptType().getOutputScript(hash); return getScriptType().getOutputScript(data);
} }
@Override @Override
public byte[] getOutputScriptData() { public byte[] getOutputScriptData() {
return hash; return data;
} }
@Override @Override

View file

@ -275,6 +275,10 @@ public class ECKey {
* use {@code new BigInteger(1, bytes);} * use {@code new BigInteger(1, bytes);}
*/ */
public static ECPoint publicPointFromPrivate(BigInteger privKey) { public static ECPoint publicPointFromPrivate(BigInteger privKey) {
if (privKey.bitLength() > CURVE.getN().bitLength()) {
privKey = privKey.mod(CURVE.getN());
}
if(Secp256k1Context.isEnabled()) { if(Secp256k1Context.isEnabled()) {
try { try {
byte[] pubKeyBytes = NativeSecp256k1.computePubkey(Utils.bigIntegerToBytes(privKey, 32), false); byte[] pubKeyBytes = NativeSecp256k1.computePubkey(Utils.bigIntegerToBytes(privKey, 32), false);
@ -285,13 +289,6 @@ public class ECKey {
} }
} }
/*
* TODO: FixedPointCombMultiplier currently doesn't support scalars longer than the group order,
* but that could change in future versions.
*/
if (privKey.bitLength() > CURVE.getN().bitLength()) {
privKey = privKey.mod(CURVE.getN());
}
return new FixedPointCombMultiplier().multiply(CURVE.getG(), privKey); return new FixedPointCombMultiplier().multiply(CURVE.getG(), privKey);
} }

View file

@ -134,10 +134,10 @@ public class PSBT {
for(TransactionOutput txOutput : transaction.getOutputs()) { for(TransactionOutput txOutput : transaction.getOutputs()) {
try { try {
Address address = txOutput.getScript().getToAddresses()[0]; Address address = txOutput.getScript().getToAddresses()[0];
if(walletTransaction.getPayments().stream().anyMatch(payment -> payment.getAddress().equals(address))) { if(walletTransaction.getAddressNodeMap().containsKey(address)) {
outputNodes.add(wallet.getWalletAddresses().getOrDefault(address, null)); outputNodes.add(walletTransaction.getAddressNodeMap().get(address));
} else if(walletTransaction.getChangeMap().keySet().stream().anyMatch(changeNode -> changeNode.getAddress().equals(address))) { } else if(walletTransaction.getChangeMap().keySet().stream().anyMatch(changeNode -> changeNode.getAddress().equals(address))) {
outputNodes.add(wallet.getWalletAddresses().getOrDefault(address, null)); outputNodes.add(walletTransaction.getChangeMap().keySet().stream().filter(changeNode -> changeNode.getAddress().equals(address)).findFirst().orElse(null));
} }
} catch(NonStandardScriptException e) { } catch(NonStandardScriptException e) {
//Ignore, likely OP_RETURN output //Ignore, likely OP_RETURN output

View file

@ -154,8 +154,12 @@ public class WalletTransaction {
getAddressNodeMap(wallet); getAddressNodeMap(wallet);
} }
public Map<Address, WalletNode> getAddressNodeMap() {
return getAddressNodeMap(getWallet());
}
public Map<Address, WalletNode> getAddressNodeMap(Wallet wallet) { public Map<Address, WalletNode> getAddressNodeMap(Wallet wallet) {
Map<Script, WalletNode> walletOutputScripts = null; Map<Address, WalletNode> walletAddresses = null;
Map<Address, WalletNode> walletAddressNodeMap = addressNodeMap.computeIfAbsent(wallet, w -> new LinkedHashMap<>()); Map<Address, WalletNode> walletAddressNodeMap = addressNodeMap.computeIfAbsent(wallet, w -> new LinkedHashMap<>());
for(Payment payment : payments) { for(Payment payment : payments) {
@ -164,11 +168,11 @@ public class WalletTransaction {
} }
if(payment.getAddress() != null && wallet != null) { if(payment.getAddress() != null && wallet != null) {
if(walletOutputScripts == null) { if(walletAddresses == null) {
walletOutputScripts = wallet.getWalletOutputScripts(); walletAddresses = wallet.getWalletAddresses();
} }
WalletNode walletNode = walletOutputScripts.get(payment.getAddress().getOutputScript()); WalletNode walletNode = walletAddresses.get(payment.getAddress());
walletAddressNodeMap.put(payment.getAddress(), walletNode); walletAddressNodeMap.put(payment.getAddress(), walletNode);
} }
} }

View file

@ -98,7 +98,7 @@ public class AddressTest {
Address address = (i % 2 == 0 ? new P2PKHAddress(values) : new P2WPKHAddress(values)); Address address = (i % 2 == 0 ? new P2PKHAddress(values) : new P2WPKHAddress(values));
String strAddress = address.toString(); String strAddress = address.toString();
Address checkAddress = Address.fromString(strAddress); Address checkAddress = Address.fromString(strAddress);
Assert.assertArrayEquals(values, checkAddress.getHash()); Assert.assertArrayEquals(values, checkAddress.getData());
} }
byte[] values32 = new byte[32]; byte[] values32 = new byte[32];
@ -107,7 +107,7 @@ public class AddressTest {
Address address = new P2WSHAddress(values32); Address address = new P2WSHAddress(values32);
String strAddress = address.toString(); String strAddress = address.toString();
Address checkAddress = Address.fromString(strAddress); Address checkAddress = Address.fromString(strAddress);
Assert.assertArrayEquals(values32, checkAddress.getHash()); Assert.assertArrayEquals(values32, checkAddress.getData());
} }
} }