From 747566d5eeb331762451bd813f678ae134311897 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 5 Jan 2023 12:17:25 +0200 Subject: [PATCH 01/31] specify junit in dependencies --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index ba4adeb..a3d667c 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ dependencies { exclude group: 'org.hamcrest', module: 'hamcrest-core' } testImplementation group: 'org.hamcrest', name: 'hamcrest-core', version: '2.2' + testImplementation 'junit:junit:4.13.1' } processResources { From c642f7414a35c9ad69439687ba8724b76d9a6fb1 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sat, 7 Jan 2023 08:22:57 +0200 Subject: [PATCH 02/31] upgrade gradle to 7.6 --- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 12 ++++++++---- gradlew.bat | 1 + 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36524 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%0DGK?7GHTj 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 VwlMN}`%er%aGR6olj~j${vQ;P=LY}) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8049c68..f398c33 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac diff --git a/gradlew.bat b/gradlew.bat index 53a6b23..6689b85 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% From 2168c56de924dd7bff5458b32f9a60a6c79066a1 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 25 Jan 2023 09:20:37 +0200 Subject: [PATCH 03/31] add tapsigner, minor refactoring --- .../java/com/sparrowwallet/drongo/Utils.java | 14 ++++++++++++++ .../sparrowwallet/drongo/bip47/PaymentCode.java | 17 ++--------------- .../com/sparrowwallet/drongo/crypto/ECKey.java | 13 +++++++++---- .../drongo/wallet/WalletModel.java | 2 +- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/Utils.java b/src/main/java/com/sparrowwallet/drongo/Utils.java index 34f8d5b..51c2f6a 100644 --- a/src/main/java/com/sparrowwallet/drongo/Utils.java +++ b/src/main/java/com/sparrowwallet/drongo/Utils.java @@ -128,6 +128,20 @@ public class Utils { return c; } + public static byte[] xor(byte[] a, byte[] b) { + if(a.length != b.length) { + throw new IllegalArgumentException("Invalid length for xor: " + a.length + " vs " + b.length); + } + + byte[] ret = new byte[a.length]; + + for(int i = 0; i < a.length; i++) { + ret[i] = (byte) ((int) b[i] ^ (int) a[i]); + } + + return ret; + } + /** Parse 4 bytes from the byte array (starting at the offset) as unsigned 32-bit integer in little endian format. */ public static long readUint32(byte[] bytes, int offset) { return (bytes[offset] & 0xffl) | diff --git a/src/main/java/com/sparrowwallet/drongo/bip47/PaymentCode.java b/src/main/java/com/sparrowwallet/drongo/bip47/PaymentCode.java index d997809..d730b71 100644 --- a/src/main/java/com/sparrowwallet/drongo/bip47/PaymentCode.java +++ b/src/main/java/com/sparrowwallet/drongo/bip47/PaymentCode.java @@ -20,6 +20,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import static com.sparrowwallet.drongo.Utils.xor; + public class PaymentCode { private static final Logger log = LoggerFactory.getLogger(PaymentCode.class); @@ -313,21 +315,6 @@ public class PaymentCode { return HDKeyDerivation.createMasterPubKeyFromBytes(pubkey, chain); } - private static byte[] xor(byte[] a, byte[] b) { - if(a.length != b.length) { - log.error("Invalid length for xor: " + a.length + " vs " + b.length); - return null; - } - - byte[] ret = new byte[a.length]; - - for(int i = 0; i < a.length; i++) { - ret[i] = (byte) ((int) b[i] ^ (int) a[i]); - } - - return ret; - } - public boolean isValid() { try { byte[] pcodeBytes = Base58.decodeChecked(strPaymentCode); diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java index 044e274..bc49ee5 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java @@ -627,6 +627,14 @@ public class ECKey { // This is what you get back from Bouncy Castle if base64 doesn't decode :( throw new SignatureException("Could not decode base64", e); } + byte[] messageBytes = formatMessageForSigning(message); + // Note that the C++ code doesn't actually seem to specify any character encoding. Presumably it's whatever + // JSON-SPIRIT hands back. Assume UTF-8 for now. + Sha256Hash messageHash = Sha256Hash.twiceOf(messageBytes); + return signedHashToKey(messageHash, signatureEncoded, electrumFormat); + } + + public static ECKey signedHashToKey(Sha256Hash messageHash, byte[] signatureEncoded, boolean electrumFormat) throws SignatureException { // Parse the signature bytes into r/s and the selector value. if(signatureEncoded.length < 65) { throw new SignatureException("Signature truncated, expected 65 bytes and got " + signatureEncoded.length); @@ -640,10 +648,7 @@ public class ECKey { BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33)); BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65)); ECDSASignature sig = new ECDSASignature(r, s); - byte[] messageBytes = formatMessageForSigning(message); - // Note that the C++ code doesn't actually seem to specify any character encoding. Presumably it's whatever - // JSON-SPIRIT hands back. Assume UTF-8 for now. - Sha256Hash messageHash = Sha256Hash.twiceOf(messageBytes); + boolean compressed = false; if(header >= 39) { // this is a bech32 signature header -= 12; diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index 2df27a7..d820cd8 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -3,7 +3,7 @@ package com.sparrowwallet.drongo.wallet; import java.util.Locale; public enum WalletModel { - SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS; + SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER; public static WalletModel getModel(String model) { return valueOf(model.toUpperCase(Locale.ROOT)); From a14b23f2fabc35c1c0b4b7b9f886dab10b4f7562 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 26 Jan 2023 15:46:56 +0200 Subject: [PATCH 04/31] add satscard for potential future use --- src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index d820cd8..f5fda81 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -3,7 +3,8 @@ package com.sparrowwallet.drongo.wallet; import java.util.Locale; public enum WalletModel { - SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER; + SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, + BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER, SATSCARD; public static WalletModel getModel(String model) { return valueOf(model.toUpperCase(Locale.ROOT)); From e2a4c32db317b9e950cfbec822cc8103332d29ff Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 27 Jan 2023 10:38:48 +0200 Subject: [PATCH 05/31] add support for external psbt signers --- .../sparrowwallet/drongo/psbt/PSBTInput.java | 18 ++++++++++++++++-- .../drongo/psbt/PSBTInputSigner.java | 11 +++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/sparrowwallet/drongo/psbt/PSBTInputSigner.java diff --git a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInput.java b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInput.java index 8bbae7e..eade24e 100644 --- a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInput.java +++ b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInput.java @@ -519,6 +519,20 @@ public class PSBTInput { } public boolean sign(ECKey privKey) { + return sign(new PSBTInputSigner() { + @Override + public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { + return privKey.sign(hash, sigHash, signatureType); + } + + @Override + public ECKey getPubKey() { + return ECKey.fromPublicOnly(privKey); + } + }); + } + + public boolean sign(PSBTInputSigner psbtInputSigner) { SigHash localSigHash = getSigHash(); if(localSigHash == null) { localSigHash = getDefaultSigHash(); @@ -529,12 +543,12 @@ public class PSBTInput { if(signingScript != null) { Sha256Hash hash = getHashForSignature(signingScript, localSigHash); TransactionSignature.Type type = isTaproot() ? SCHNORR : ECDSA; - TransactionSignature transactionSignature = privKey.sign(hash, localSigHash, type); + TransactionSignature transactionSignature = psbtInputSigner.sign(hash, localSigHash, type); if(type == SCHNORR) { tapKeyPathSignature = transactionSignature; } else { - ECKey pubKey = ECKey.fromPublicOnly(privKey); + ECKey pubKey = psbtInputSigner.getPubKey(); getPartialSignatures().put(pubKey, transactionSignature); } diff --git a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInputSigner.java b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInputSigner.java new file mode 100644 index 0000000..6d73fb4 --- /dev/null +++ b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTInputSigner.java @@ -0,0 +1,11 @@ +package com.sparrowwallet.drongo.psbt; + +import com.sparrowwallet.drongo.crypto.ECKey; +import com.sparrowwallet.drongo.protocol.Sha256Hash; +import com.sparrowwallet.drongo.protocol.SigHash; +import com.sparrowwallet.drongo.protocol.TransactionSignature; + +public interface PSBTInputSigner { + TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType); + ECKey getPubKey(); +} From b487396417fbdf3c73c24399a778855c97a26584 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 30 Jan 2023 09:40:35 +0200 Subject: [PATCH 06/31] add support for external message signers --- .../java/com/sparrowwallet/drongo/crypto/ECKey.java | 10 +++++++++- .../com/sparrowwallet/drongo/wallet/WalletModel.java | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java index bc49ee5..996456c 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/ECKey.java @@ -576,9 +576,13 @@ public class ECKey { * @throws IllegalStateException if this ECKey does not have the private part. */ public String signMessage(String message, ScriptType scriptType) { + return signMessage(message, scriptType, this::signEcdsa); + } + + public String signMessage(String message, ScriptType scriptType, ECDSAHashSigner ecdsaHashSigner) { byte[] data = formatMessageForSigning(message); Sha256Hash hash = Sha256Hash.twiceOf(data); - ECDSASignature sig = signEcdsa(hash); + ECDSASignature sig = ecdsaHashSigner.sign(hash); byte recId = findRecoveryId(hash, sig); int headerByte = recId + getSigningTypeConstant(scriptType); byte[] sigData = new byte[65]; // 1 header + 32 bytes for R + 32 bytes for S @@ -868,4 +872,8 @@ public class ECKey { throw new RuntimeException(e); // Cannot happen. } } + + public interface ECDSAHashSigner { + ECDSASignature sign(Sha256Hash hash); + } } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index f5fda81..4abf6c5 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -66,6 +66,10 @@ public enum WalletModel { return (this == TREZOR_1 || this == KEEPKEY); } + public boolean isCard() { + return (this == TAPSIGNER || this == SATSCARD); + } + public static WalletModel fromType(String type) { for(WalletModel model : values()) { if(model.getType().equalsIgnoreCase(type)) { From d48054ac6ba071b49180017fe12e3acb41635b9c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 8 Feb 2023 08:02:22 +0200 Subject: [PATCH 07/31] add support for creating output descriptors without rendering xpubs --- .../drongo/OutputDescriptor.java | 30 +++++++++++-------- .../drongo/wallet/WalletModel.java | 2 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java index c5d17d7..cf4defe 100644 --- a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java +++ b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java @@ -479,6 +479,10 @@ public class OutputDescriptor { } public String toString(boolean addKeyOrigin, boolean addChecksum) { + return toString(addKeyOrigin, true, addChecksum); + } + + public String toString(boolean addKeyOrigin, boolean addKey, boolean addChecksum) { StringBuilder builder = new StringBuilder(); builder.append(scriptType.getDescriptor()); @@ -487,14 +491,14 @@ public class OutputDescriptor { StringJoiner joiner = new StringJoiner(","); joiner.add(Integer.toString(multisigThreshold)); for(ExtendedKey pubKey : sortExtendedPubKeys(extendedPublicKeys.keySet())) { - String extKeyString = toString(pubKey, addKeyOrigin); + String extKeyString = toString(pubKey, addKeyOrigin, addKey); joiner.add(extKeyString); } builder.append(joiner.toString()); builder.append(ScriptType.MULTISIG.getCloseDescriptor()); } else { ExtendedKey extendedPublicKey = getSingletonExtendedPublicKey(); - builder.append(toString(extendedPublicKey, addKeyOrigin)); + builder.append(toString(extendedPublicKey, addKeyOrigin, addKey)); } builder.append(scriptType.getCloseDescriptor()); @@ -548,7 +552,7 @@ public class OutputDescriptor { } } - private String toString(ExtendedKey pubKey, boolean addKeyOrigin) { + private String toString(ExtendedKey pubKey, boolean addKeyOrigin, boolean addKey) { StringBuilder keyBuilder = new StringBuilder(); KeyDerivation keyDerivation = extendedPublicKeys.get(pubKey); if(keyDerivation != null && keyDerivation.getDerivationPath() != null && addKeyOrigin) { @@ -561,17 +565,19 @@ public class OutputDescriptor { keyBuilder.append("]"); } - if(pubKey != null) { - keyBuilder.append(pubKey.toString()); - } - - String childDerivation = mapChildrenDerivations.get(pubKey); - if(childDerivation != null) { - if(!childDerivation.startsWith("/")) { - keyBuilder.append("/"); + if(addKey) { + if(pubKey != null) { + keyBuilder.append(pubKey.toString()); } - keyBuilder.append(childDerivation); + String childDerivation = mapChildrenDerivations.get(pubKey); + if(childDerivation != null) { + if(!childDerivation.startsWith("/")) { + keyBuilder.append("/"); + } + + keyBuilder.append(childDerivation); + } } return keyBuilder.toString(); diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index 4abf6c5..fcb4234 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -4,7 +4,7 @@ import java.util.Locale; public enum WalletModel { SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, - BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER, SATSCARD; + BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER, SATSCARD, LABELS; public static WalletModel getModel(String model) { return valueOf(model.toUpperCase(Locale.ROOT)); From 883b1c95b4e8bd961fb07ff09327d9da4a5bcb9d Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 10 Feb 2023 09:22:39 +0200 Subject: [PATCH 08/31] recompile secp256k1 on osx 10.13.6 --- .../native/osx/x64/libsecp256k1.dylib | Bin 387832 -> 334160 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/native/osx/x64/libsecp256k1.dylib b/src/main/resources/native/osx/x64/libsecp256k1.dylib index 1f4c932b9b5a36cba70296931158bba4a19d4bf2..86a426b5ff97a7e1a6864e9a3e332f411f0f41f7 100755 GIT binary patch delta 105955 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 G%>M>7L0$I% delta 125825 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 Kc`5qH%Krj1wNa!1 From 0002d6bae69feb4a5195418ae99d520653c5e7dc Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 13 Feb 2023 16:35:40 +0200 Subject: [PATCH 09/31] support detection of utf8 string script chunks --- .../java/com/sparrowwallet/drongo/Utils.java | 11 ++++++++ .../drongo/protocol/ScriptChunk.java | 25 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/Utils.java b/src/main/java/com/sparrowwallet/drongo/Utils.java index 51c2f6a..4d7136f 100644 --- a/src/main/java/com/sparrowwallet/drongo/Utils.java +++ b/src/main/java/com/sparrowwallet/drongo/Utils.java @@ -13,6 +13,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.nio.ByteBuffer; +import java.nio.charset.CharsetDecoder; import java.nio.charset.StandardCharsets; import java.util.*; @@ -31,6 +32,16 @@ public class Utils { return s.matches(BASE64_REGEX); } + public static boolean isUtf8(byte[] bytes) { + try { + CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); + decoder.decode(java.nio.ByteBuffer.wrap(bytes)); + return true; + } catch(Exception e) { + return false; + } + } + public static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for ( int j = 0; j < bytes.length; j++ ) { diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java index f74b4d4..ce559a1 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java @@ -7,6 +7,8 @@ import org.bouncycastle.util.encoders.Hex; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; @@ -28,7 +30,11 @@ public class ScriptChunk { } public static ScriptChunk fromOpcode(int opcode) { - return new ScriptChunk(opcode, null); + return new ScriptChunk(opcode, opcode == ScriptOpCodes.OP_0 ? new byte[0] : null); + } + + public static ScriptChunk fromString(String strData, Charset charset) { + return fromData(strData.getBytes(charset)); } public static ScriptChunk fromData(byte[] data) { @@ -68,7 +74,7 @@ public class ScriptChunk { } public void write(OutputStream stream) throws IOException { - if (isOpCode()) { + if (isOpCode() && opcode != ScriptOpCodes.OP_0) { if(data != null) throw new IllegalStateException("Data must be null for opcode chunk"); stream.write(opcode); } else if (data != null) { @@ -126,6 +132,18 @@ public class ScriptChunk { } } + public boolean isString() { + if(data == null || data.length == 0) { + return false; + } + + if(isSignature() || isPubKey()) { + return false; + } + + return Utils.isUtf8(data); + } + public boolean isScript() { if(data == null || data.length == 0) { return false; @@ -213,6 +231,9 @@ public class ScriptChunk { if (data.length == 0) { return "OP_0"; } + if(Utils.isUtf8(data)) { + return new String(data, StandardCharsets.UTF_8); + } return Hex.toHexString(data); } From 22e70fd8e5adce51f3e84254ea4696c24b42e707 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 13 Feb 2023 17:04:20 +0200 Subject: [PATCH 10/31] fix taproot signature hash for single | anyonecanpay --- .../java/com/sparrowwallet/drongo/protocol/Transaction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java b/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java index c4ca948..d978ab1 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java @@ -685,7 +685,7 @@ public class Transaction extends ChildMessage { if(anyoneCanPay) { getInputs().get(inputIndex).getOutpoint().bitcoinSerializeToStream(bos); - Utils.uint32ToByteStreamLE(spentUtxos.get(inputIndex).getValue(), bos); + Utils.int64ToByteStreamLE(spentUtxos.get(inputIndex).getValue(), bos); byteArraySerialize(spentUtxos.get(inputIndex).getScriptBytes(), bos); Utils.uint32ToByteStreamLE(getInputs().get(inputIndex).getSequenceNumber(), bos); } else { From 46c4b332065cdad01314d0430882814a88e72171 Mon Sep 17 00:00:00 2001 From: samouraidev Date: Fri, 17 Feb 2023 09:11:34 +0100 Subject: [PATCH 11/31] Modify group value test --- .../java/com/sparrowwallet/drongo/bip47/PaymentAddress.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/bip47/PaymentAddress.java b/src/main/java/com/sparrowwallet/drongo/bip47/PaymentAddress.java index fc9054d..3558787 100644 --- a/src/main/java/com/sparrowwallet/drongo/bip47/PaymentAddress.java +++ b/src/main/java/com/sparrowwallet/drongo/bip47/PaymentAddress.java @@ -71,7 +71,7 @@ public class PaymentAddress { private BigInteger addSecp256k1(BigInteger b1, BigInteger b2) { BigInteger ret = b1.add(b2); - if(ret.bitLength() > CURVE.getN().bitLength()) { + if(ret.compareTo(CURVE.getN()) > 0) { return ret.mod(CURVE.getN()); } @@ -83,7 +83,7 @@ public class PaymentAddress { } private boolean isSecp256k1(BigInteger b) { - return b.compareTo(BigInteger.ONE) > 0 && b.bitLength() <= CURVE.getN().bitLength(); + return (b.compareTo(BigInteger.ONE) > 0) && (b.compareTo(CURVE.getN()) < 0); } private BigInteger secretPoint() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, NotSecp256k1Exception { From caed93ca6d3e29433c13ed9db705e34e057caf43 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 22 Feb 2023 10:19:02 +0200 Subject: [PATCH 12/31] minor additions to support bip129 --- src/main/java/com/sparrowwallet/drongo/Utils.java | 5 +++++ .../drongo/crypto/Pbkdf2KeyDeriver.java | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/Utils.java b/src/main/java/com/sparrowwallet/drongo/Utils.java index 4d7136f..554c279 100644 --- a/src/main/java/com/sparrowwallet/drongo/Utils.java +++ b/src/main/java/com/sparrowwallet/drongo/Utils.java @@ -23,6 +23,7 @@ public class Utils { public static final String HEX_REGEX = "^[0-9A-Fa-f]+$"; public static final String BASE64_REGEX = "^[0-9A-Za-z\\\\+=/]+$"; + public static final String NUMERIC_REGEX = "^-?\\d+(\\.\\d+)?$"; public static boolean isHex(String s) { return s.matches(HEX_REGEX); @@ -32,6 +33,10 @@ public class Utils { return s.matches(BASE64_REGEX); } + public static boolean isNumber(String s) { + return s.matches(NUMERIC_REGEX); + } + public static boolean isUtf8(byte[] bytes) { try { CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Pbkdf2KeyDeriver.java b/src/main/java/com/sparrowwallet/drongo/crypto/Pbkdf2KeyDeriver.java index 578b27b..d3e57dc 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Pbkdf2KeyDeriver.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Pbkdf2KeyDeriver.java @@ -7,25 +7,36 @@ import org.bouncycastle.crypto.params.KeyParameter; public class Pbkdf2KeyDeriver implements KeyDeriver, AsymmetricKeyDeriver { public static final int DEFAULT_ITERATION_COUNT = 1024; + public static final int DEFAULT_KEY_SIZE = 512; private final byte[] salt; private final int iterationCount; + private final int keySize; public static final Pbkdf2KeyDeriver DEFAULT_INSTANCE = new Pbkdf2KeyDeriver(); public Pbkdf2KeyDeriver() { this.salt = new byte[0]; this.iterationCount = DEFAULT_ITERATION_COUNT; + this.keySize = DEFAULT_KEY_SIZE; } public Pbkdf2KeyDeriver(byte[] salt) { this.salt = salt; this.iterationCount = DEFAULT_ITERATION_COUNT; + this.keySize = DEFAULT_KEY_SIZE; } public Pbkdf2KeyDeriver(byte[] salt, int iterationCount) { this.salt = salt; this.iterationCount = iterationCount; + this.keySize = DEFAULT_KEY_SIZE; + } + + public Pbkdf2KeyDeriver(byte[] salt, int iterationCount, int keySize) { + this.salt = salt; + this.iterationCount = iterationCount; + this.keySize = keySize; } @Override @@ -37,7 +48,7 @@ public class Pbkdf2KeyDeriver implements KeyDeriver, AsymmetricKeyDeriver { public Key deriveKey(CharSequence password) throws KeyCrypterException { PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA512Digest()); gen.init(SecureString.toBytesUTF8(password), salt, iterationCount); - byte[] keyBytes = ((KeyParameter)gen.generateDerivedParameters(512)).getKey(); + byte[] keyBytes = ((KeyParameter)gen.generateDerivedParameters(keySize)).getKey(); return new Key(keyBytes, salt, getDeriverType()); } From d0da764aadfc9edc2a7fb35540eca0ee4c20ba0f Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 23 Feb 2023 11:59:47 +0200 Subject: [PATCH 13/31] add bsms model, additional taproot signing check --- .../com/sparrowwallet/drongo/protocol/Transaction.java | 8 ++++---- .../java/com/sparrowwallet/drongo/wallet/WalletModel.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java b/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java index d978ab1..25f0102 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/Transaction.java @@ -8,10 +8,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; +import java.util.*; import static com.sparrowwallet.drongo.Utils.uint32ToByteStreamLE; import static com.sparrowwallet.drongo.Utils.uint64ToByteStreamLE; @@ -634,6 +631,9 @@ public class Transaction extends ChildMessage { if(spentUtxos.size() != getInputs().size()) { throw new IllegalArgumentException("Provided spent UTXOs length does not equal the number of transaction inputs"); } + if(spentUtxos.stream().anyMatch(Objects::isNull)) { + throw new IllegalArgumentException("Not all spent UTXOs are provided"); + } if(inputIndex >= getInputs().size()) { throw new IllegalArgumentException("Input index is greater than the number of transaction inputs"); } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index fcb4234..49b56a4 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -4,7 +4,7 @@ import java.util.Locale; public enum WalletModel { SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, - BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER, SATSCARD, LABELS; + BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE, LEDGER_NANO_S_PLUS, EPS, TAPSIGNER, SATSCARD, LABELS, BSMS; public static WalletModel getModel(String model) { return valueOf(model.toUpperCase(Locale.ROOT)); From 0f78efc373e99cf48a749ced25cd112ca083b88f Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 28 Feb 2023 09:55:51 +0200 Subject: [PATCH 14/31] support converting xprvs to xpubs in output descriptors --- src/main/java/com/sparrowwallet/drongo/ExtendedKey.java | 4 ++-- .../java/com/sparrowwallet/drongo/OutputDescriptor.java | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java b/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java index 37efd09..67b1d50 100644 --- a/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java +++ b/src/main/java/com/sparrowwallet/drongo/ExtendedKey.java @@ -90,8 +90,8 @@ public class ExtendedKey { ChildNumber childNumber; List path; - if(depth == 0) { - //Poorly formatted extended key, add first child path element + if(depth == 0 && !header.isPrivateKey()) { + //Poorly formatted public extended key, add first child path element childNumber = new ChildNumber(0, false); } else if ((i & ChildNumber.HARDENED_BIT) != 0) { childNumber = new ChildNumber(i ^ ChildNumber.HARDENED_BIT, true); //already hardened diff --git a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java index cf4defe..6698930 100644 --- a/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java +++ b/src/main/java/com/sparrowwallet/drongo/OutputDescriptor.java @@ -22,7 +22,7 @@ public class OutputDescriptor { private static final String INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; private static final String CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - private static final Pattern XPUB_PATTERN = Pattern.compile("(\\[[^\\]]+\\])?(.pub[^/\\,)]{100,112})(/[/\\d*'hH<>;]+)?"); + private static final Pattern XPUB_PATTERN = Pattern.compile("(\\[[^\\]]+\\])?(.(?:pub|prv)[^/\\,)]{100,112})(/[/\\d*'hH<>;]+)?"); private static final Pattern PUBKEY_PATTERN = Pattern.compile("(\\[[^\\]]+\\])?(0[23][0-9a-fA-F]{32})"); private static final Pattern MULTI_PATTERN = Pattern.compile("multi\\(([\\d+])"); private static final Pattern KEY_ORIGIN_PATTERN = Pattern.compile("\\[([A-Fa-f0-9]{8})([/\\d'hH]+)\\]"); @@ -379,6 +379,13 @@ public class OutputDescriptor { KeyDerivation keyDerivation = new KeyDerivation(masterFingerprint, keyDerivationPath); try { ExtendedKey extendedPublicKey = ExtendedKey.fromDescriptor(extPubKey); + if(extendedPublicKey.getKey().hasPrivKey()) { + List derivation = keyDerivation.getDerivation(); + int depth = derivation.size() == 0 ? scriptType.getDefaultDerivation().size() : derivation.size(); + DeterministicKey prvKey = extendedPublicKey.getKey(); + DeterministicKey pubKey = new DeterministicKey(prvKey.getPath(), prvKey.getChainCode(), prvKey.getPubKey(), depth, extendedPublicKey.getParentFingerprint()); + extendedPublicKey = new ExtendedKey(pubKey, pubKey.getParentFingerprint(), extendedPublicKey.getKeyChildNumber()); + } keyDerivationMap.put(extendedPublicKey, keyDerivation); keyChildDerivationMap.put(extendedPublicKey, childDerivationPath); } catch(ProtocolException e) { From 7eab644cecc71e591ba805cff1a408b9f31a9303 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 7 Mar 2023 13:16:49 +0200 Subject: [PATCH 15/31] support serialization of psbts without non witness utxo input entries --- src/main/java/com/sparrowwallet/drongo/psbt/PSBT.java | 11 ++++++----- .../com/sparrowwallet/drongo/wallet/WalletModel.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/psbt/PSBT.java b/src/main/java/com/sparrowwallet/drongo/psbt/PSBT.java index cf79731..3c86bed 100644 --- a/src/main/java/com/sparrowwallet/drongo/psbt/PSBT.java +++ b/src/main/java/com/sparrowwallet/drongo/psbt/PSBT.java @@ -461,10 +461,10 @@ public class PSBT { } public byte[] serialize() { - return serialize(true); + return serialize(true, true); } - public byte[] serialize(boolean includeXpubs) { + public byte[] serialize(boolean includeXpubs, boolean includeNonWitnessUtxos) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.writeBytes(Utils.hexToBytes(PSBT_MAGIC_HEX)); @@ -481,8 +481,9 @@ public class PSBT { for(PSBTInput psbtInput : getPsbtInputs()) { List inputEntries = psbtInput.getInputEntries(); for(PSBTEntry entry : inputEntries) { - if(includeXpubs || (entry.getKeyType() != PSBT_IN_BIP32_DERIVATION && entry.getKeyType() != PSBT_IN_PROPRIETARY - && entry.getKeyType() != PSBT_IN_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_IN_TAP_BIP32_DERIVATION)) { + if((includeXpubs || (entry.getKeyType() != PSBT_IN_BIP32_DERIVATION && entry.getKeyType() != PSBT_IN_PROPRIETARY + && entry.getKeyType() != PSBT_IN_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_IN_TAP_BIP32_DERIVATION)) + && (includeNonWitnessUtxos || entry.getKeyType() != PSBT_IN_NON_WITNESS_UTXO)) { entry.serializeToStream(baos); } } @@ -630,7 +631,7 @@ public class PSBT { } public String toBase64String(boolean includeXpubs) { - return Base64.toBase64String(serialize(includeXpubs)); + return Base64.toBase64String(serialize(includeXpubs, true)); } public static boolean isPSBT(byte[] b) { diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java index 49b56a4..66586f1 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletModel.java @@ -51,7 +51,7 @@ public enum WalletModel { } public boolean alwaysIncludeNonWitnessUtxo() { - if(this == COLDCARD || this == COBO_VAULT || this == PASSPORT || this == KEYSTONE || this == GORDIAN_SEED_TOOL) { + if(this == COLDCARD || this == COBO_VAULT || this == PASSPORT || this == KEYSTONE || this == GORDIAN_SEED_TOOL || this == SEEDSIGNER) { return false; } From fe19c86544d75d0ce0d8c32b0cbbd44de64ae463 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Wed, 22 Mar 2023 15:49:18 +0200 Subject: [PATCH 16/31] add functionality to determine possible last bip39 words --- .../drongo/wallet/Bip39MnemonicCode.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Bip39MnemonicCode.java b/src/main/java/com/sparrowwallet/drongo/wallet/Bip39MnemonicCode.java index 3dc0d21..a32b291 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Bip39MnemonicCode.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Bip39MnemonicCode.java @@ -229,4 +229,85 @@ public class Bip39MnemonicCode { bits[(i * 8) + j] = (data[i] & (1 << (7 - j))) != 0; return bits; } + + public List getPossibleLastWords(List previousWords) throws MnemonicException.MnemonicLengthException, MnemonicException.MnemonicWordException { + if((previousWords.size() + 1) % 3 > 0) { + throw new MnemonicException.MnemonicLengthException("Previous word list size must be multiple of three words, less one."); + } + + // Look up all the words in the list and construct the + // concatenation of the original entropy and the checksum. + // + int concatLenBits = previousWords.size() * 11; + boolean[] concatBits = new boolean[concatLenBits]; + int wordindex = 0; + for (String word : previousWords) { + // Find the words index in the wordlist. + int ndx = Collections.binarySearch(this.wordList, word); + if (ndx < 0) { + throw new MnemonicException.MnemonicWordException(word); + } + // Set the next 11 bits to the value of the index. + for (int ii = 0; ii < 11; ++ii) { + concatBits[(wordindex * 11) + ii] = (ndx & (1 << (10 - ii))) != 0; + } + ++wordindex; + } + + int checksumLengthBits = (concatLenBits + 11) / 33; + int entropyLengthBits = (concatLenBits + 11) - checksumLengthBits; + int varyingLengthBits = entropyLengthBits - concatLenBits; + + boolean[][] bitPermutations = getBitPermutations(varyingLengthBits); + + ArrayList possibleWords = new ArrayList<>(); + for(boolean[] bitPermutation : bitPermutations) { + boolean[] entropyBits = new boolean[concatLenBits + varyingLengthBits]; + System.arraycopy(concatBits, 0, entropyBits, 0, concatBits.length); + System.arraycopy(bitPermutation, 0, entropyBits, concatBits.length, varyingLengthBits); + + byte[] entropy = new byte[entropyLengthBits / 8]; + for(int ii = 0; ii < entropy.length; ++ii) { + for(int jj = 0; jj < 8; ++jj) { + if(entropyBits[(ii * 8) + jj]) { + entropy[ii] |= 1 << (7 - jj); + } + } + } + + byte[] hash = Sha256Hash.hash(entropy); + boolean[] hashBits = bytesToBits(hash); + + boolean[] wordBits = new boolean[11]; + System.arraycopy(bitPermutation, 0, wordBits, 0, varyingLengthBits); + System.arraycopy(hashBits, 0, wordBits, varyingLengthBits, checksumLengthBits); + + int index = 0; + for(int j = 0; j < 11; ++j) { + index <<= 1; + if(wordBits[j]) { + index |= 0x1; + } + } + + possibleWords.add(this.wordList.get(index)); + } + + Collections.sort(possibleWords); + + return possibleWords; + } + + public static boolean[][] getBitPermutations(int length) { + int numPermutations = (int) Math.pow(2, length); + boolean[][] permutations = new boolean[numPermutations][length]; + + for (int i = 0; i < numPermutations; i++) { + for (int j = 0; j < length; j++) { + permutations[i][j] = ((i >> j) & 1) == 1; + } + } + + return permutations; + } } From b26c5e5218b91c760b7f63f47d93b7301223cc2c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 15 May 2023 15:29:18 -0500 Subject: [PATCH 17/31] support compact seedqrs with high ec --- src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java b/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java index 30231cd..9bf9036 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java @@ -41,10 +41,12 @@ public class SeedQR { String qrHex = Utils.bytesToHex(compactSeedQr); String seedHex; - if(qrHex.endsWith("0ec")) { - seedHex = qrHex.substring(3, qrHex.length() - 3); + if(qrHex.endsWith("0ec11ec11")) { + seedHex = qrHex.substring(3, qrHex.length() - 9); //12 word, high EC + } else if(qrHex.endsWith("0ec")) { + seedHex = qrHex.substring(3, qrHex.length() - 3); //12 word, low EC } else { - seedHex = qrHex.substring(3, qrHex.length() - 1); + seedHex = qrHex.substring(3, qrHex.length() - 1); //24 word } byte[] seed = Utils.hexToBytes(seedHex); From 5b9b3043a6fded8e6f1589327a9fa2718b41f90c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 1 Jun 2023 15:30:06 +0200 Subject: [PATCH 18/31] minor changes to support adding additional rbf tx inputs --- .../drongo/wallet/InsufficientFundsException.java | 11 +++++++++++ .../drongo/wallet/PresetUtxoSelector.java | 11 +++++++++++ .../java/com/sparrowwallet/drongo/wallet/Wallet.java | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/InsufficientFundsException.java b/src/main/java/com/sparrowwallet/drongo/wallet/InsufficientFundsException.java index dca047e..3229edf 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/InsufficientFundsException.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/InsufficientFundsException.java @@ -1,6 +1,8 @@ package com.sparrowwallet.drongo.wallet; public class InsufficientFundsException extends Exception { + private Long targetValue; + public InsufficientFundsException() { super(); } @@ -8,4 +10,13 @@ public class InsufficientFundsException extends Exception { public InsufficientFundsException(String msg) { super(msg); } + + public InsufficientFundsException(String message, Long targetValue) { + super(message); + this.targetValue = targetValue; + } + + public Long getTargetValue() { + return targetValue; + } } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java index 090014c..996fd17 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java @@ -7,15 +7,22 @@ import java.util.stream.Collectors; public class PresetUtxoSelector extends SingleSetUtxoSelector { private final Collection presetUtxos; + private final Collection excludedUtxos; private final boolean maintainOrder; public PresetUtxoSelector(Collection presetUtxos) { + this(presetUtxos, new ArrayList<>()); + } + + public PresetUtxoSelector(Collection presetUtxos, Collection excludedUtxos) { this.presetUtxos = presetUtxos; + this.excludedUtxos = excludedUtxos; this.maintainOrder = false; } public PresetUtxoSelector(Collection presetUtxos, boolean maintainOrder) { this.presetUtxos = presetUtxos; + this.excludedUtxos = new ArrayList<>(); this.maintainOrder = maintainOrder; } @@ -44,6 +51,10 @@ public class PresetUtxoSelector extends SingleSetUtxoSelector { return presetUtxos; } + public Collection getExcludedUtxos() { + return excludedUtxos; + } + @Override public boolean shuffleInputs() { return !maintainOrder; diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 5e13524..d828cc8 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -1224,7 +1224,7 @@ public class Wallet extends Persistable implements Comparable { } } - throw new InsufficientFundsException("Not enough combined value in UTXOs for output value " + targetValue); + throw new InsufficientFundsException("Not enough combined value in UTXOs for output value " + targetValue, targetValue); } private List getGroupedUtxos(List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { From d3e003f76e15e2808a30107e040d519c84393bfa Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sun, 4 Jun 2023 10:01:42 +0200 Subject: [PATCH 19/31] fix reading of compact size int as unsigned short when parsing psbts --- src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java index fa4326d..54be38f 100644 --- a/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java +++ b/src/main/java/com/sparrowwallet/drongo/psbt/PSBTEntry.java @@ -188,7 +188,7 @@ public class PSBTEntry { psbtByteBuffer.get(buf); ByteBuffer byteBuffer = ByteBuffer.wrap(buf); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - return byteBuffer.getShort(); + return Short.toUnsignedInt(byteBuffer.getShort()); } case (byte) 0xfe: { byte[] buf = new byte[4]; From a8df17ff5eb906cf1d929f978fdad34bb244ce55 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 5 Jun 2023 11:41:41 +0200 Subject: [PATCH 20/31] continue with transaction parsing if pushdata opcode is found with invalid data length --- .../sparrowwallet/drongo/protocol/Script.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/Script.java b/src/main/java/com/sparrowwallet/drongo/protocol/Script.java index b79025e..b821092 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/Script.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/Script.java @@ -4,6 +4,8 @@ import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.address.*; import com.sparrowwallet.drongo.crypto.ECKey; import org.bouncycastle.util.encoders.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -18,6 +20,8 @@ import static com.sparrowwallet.drongo.protocol.ScriptType.*; import static com.sparrowwallet.drongo.protocol.ScriptOpCodes.*; public class Script { + private static final Logger log = LoggerFactory.getLogger(Script.class); + public static final long MAX_SCRIPT_ELEMENT_SIZE = 520; // The program is a set of chunks where each element is either [opcode] or [data, data, data ...] @@ -32,7 +36,11 @@ public class Script { Script(byte[] programBytes, boolean parse) { program = programBytes; if(parse) { - parse(); + try { + parse(); + } catch(ProtocolException e) { + log.warn("Invalid script, continuing with already parsed chunks", e); + } } } @@ -59,16 +67,16 @@ public class Script { // Read some bytes of data, where how many is the opcode value itself. dataToRead = opcode; } else if (opcode == OP_PUSHDATA1) { - if (bis.available() < 1) throw new ProtocolException("Unexpected end of script"); + if (bis.available() < 1) throw new ProtocolException("Unexpected end of script - OP_PUSHDATA1 was followed by " + bis.available() + " bytes"); dataToRead = bis.read(); } else if (opcode == OP_PUSHDATA2) { // Read a short, then read that many bytes of data. - if (bis.available() < 2) throw new ProtocolException("Unexpected end of script"); + if (bis.available() < 2) throw new ProtocolException("Unexpected end of script - OP_PUSHDATA2 was followed by only " + bis.available() + " bytes"); dataToRead = Utils.readUint16FromStream(bis); } else if (opcode == OP_PUSHDATA4) { // Read a uint32, then read that many bytes of data. // Though this is allowed, because its value cannot be > 520, it should never actually be used - if (bis.available() < 4) throw new ProtocolException("Unexpected end of script"); + if (bis.available() < 4) throw new ProtocolException("Unexpected end of script - OP_PUSHDATA4 was followed by only " + bis.available() + " bytes"); dataToRead = Utils.readUint32FromStream(bis); } From d5abf351bedc2e4234f14a1f3883feb9de6803be Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 23 Jun 2023 09:51:44 +0200 Subject: [PATCH 21/31] retain utxo frozen status on wallet refresh --- src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java | 4 ++++ .../java/com/sparrowwallet/drongo/wallet/WalletNode.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index d828cc8..267d493 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -1660,6 +1660,10 @@ public class Wallet extends Persistable implements Comparable { labels.put(output.getHash().toString() + "<" + output.getIndex(), output.getLabel()); } + if(output.getStatus() != null) { + labels.put(output.getHash().toString() + ":" + output.getIndex(), output.getStatus().toString()); + } + if(output.isSpent() && output.getSpentBy().getLabel() != null && !output.getSpentBy().getLabel().isEmpty()) { labels.put(output.getSpentBy().getHash() + ">" + output.getSpentBy().getIndex(), output.getSpentBy().getLabel()); } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java index 484e5cd..4882606 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java @@ -149,6 +149,11 @@ public class WalletNode extends Persistable implements Comparable { txo.setLabel(label); } + String status = wallet.getDetachedLabels().remove(txo.getHash().toString() + ":" + txo.getIndex()); + if(status != null && txo.getStatus() == null) { + txo.setStatus(Status.valueOf(status)); + } + if(txo.isSpent()) { String spentByLabel = wallet.getDetachedLabels().remove(txo.getSpentBy().getHash() + ">" + txo.getSpentBy().getIndex()); if(spentByLabel != null && (txo.getSpentBy().getLabel() == null || txo.getSpentBy().getLabel().isEmpty())) { From 4341973acd9577def1d8fee486718bf5eca9b771 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 30 Jun 2023 08:59:08 +0200 Subject: [PATCH 22/31] add method for sha256 deserialization mappers --- .../sparrowwallet/drongo/protocol/Sha256Hash.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/Sha256Hash.java b/src/main/java/com/sparrowwallet/drongo/protocol/Sha256Hash.java index 11c0269..ce3650d 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/Sha256Hash.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/Sha256Hash.java @@ -61,6 +61,18 @@ public class Sha256Hash implements Comparable { return wrap(Utils.hexToBytes(hexString)); } + /** + * Duplicate method with default name for deserialization mappers. + * + * @param hexString a hash value represented as a hex string + * @return a new instance + * @throws IllegalArgumentException if the given string is not a valid + * hex string, or if it does not represent exactly 32 bytes + */ + public static Sha256Hash fromString(String hexString) { + return wrap(hexString); + } + /** * Creates a new instance that wraps the given hash value, but with byte order reversed. * From c0555c3fb053ed8e8fbba2249151c90eebc7d649 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 30 Jun 2023 12:50:43 +0200 Subject: [PATCH 23/31] implement bip322 for p2wpkh and p2tr singlesig addresses --- .../sparrowwallet/drongo/crypto/Bip322.java | 122 ++++++++++++++++++ .../drongo/protocol/TransactionSignature.java | 2 +- .../drongo/crypto/Bip322Test.java | 118 +++++++++++++++++ 3 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java create mode 100644 src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java new file mode 100644 index 0000000..c6a3304 --- /dev/null +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -0,0 +1,122 @@ +package com.sparrowwallet.drongo.crypto; + +import com.sparrowwallet.drongo.Utils; +import com.sparrowwallet.drongo.address.Address; +import com.sparrowwallet.drongo.protocol.*; +import com.sparrowwallet.drongo.psbt.PSBT; +import com.sparrowwallet.drongo.psbt.PSBTInput; +import com.sparrowwallet.drongo.psbt.PSBTInputSigner; +import com.sparrowwallet.drongo.psbt.PSBTSignatureException; + +import java.nio.charset.StandardCharsets; +import java.security.SignatureException; +import java.util.*; + +import static com.sparrowwallet.drongo.protocol.ScriptType.P2TR; + +public class Bip322 { + public static String signMessageBip322(Address address, String message, PSBTInputSigner psbtInputSigner) { + Transaction toSpend = getBip322ToSpend(address, message); + Transaction toSign = getBip322ToSign(toSpend); + + TransactionOutput utxoOutput = toSpend.getOutputs().get(0); + + PSBT psbt = new PSBT(toSign); + PSBTInput psbtInput = psbt.getPsbtInputs().get(0); + psbtInput.setWitnessUtxo(utxoOutput); + psbtInput.setSigHash(SigHash.ALL); + psbtInput.sign(psbtInputSigner); + + ECKey pubKey = psbtInputSigner.getPubKey(); + TransactionSignature signature = psbtInput.isTaproot() ? psbtInput.getTapKeyPathSignature() : psbtInput.getPartialSignature(pubKey); + + Transaction finalizeTransaction = new Transaction(); + TransactionInput finalizedTxInput = address.getScriptType().addSpendingInput(finalizeTransaction, utxoOutput, pubKey, signature); + + return Base64.getEncoder().encodeToString(finalizedTxInput.getWitness().toByteArray()); + } + + public static void verifyMessageBip322(Address address, String message, String signatureBase64) throws SignatureException { + byte[] signatureEncoded; + try { + signatureEncoded = Base64.getDecoder().decode(signatureBase64); + } catch(IllegalArgumentException e) { + throw new SignatureException("Could not decode base64 signature", e); + } + + TransactionWitness witness = new TransactionWitness(null, signatureEncoded, 0); + TransactionSignature signature; + ECKey pubKey; + + if(address.getScriptType() == ScriptType.P2WPKH) { + signature = witness.getSignatures().get(0); + pubKey = ECKey.fromPublicOnly(witness.getPushes().get(1)); + + if(!address.equals(address.getScriptType().getAddress(pubKey))) { + throw new SignatureException("Provided address does not match pubkey in signature"); + } + } else if(address.getScriptType() == ScriptType.P2TR) { + signature = witness.getSignatures().get(0); + pubKey = P2TR.getPublicKeyFromScript(address.getOutputScript()); + } else { + throw new IllegalArgumentException(address.getScriptType() + " addresses are not supported"); + } + + Transaction toSpend = getBip322ToSpend(address, message); + Transaction toSign = getBip322ToSign(toSpend); + + PSBT psbt = new PSBT(toSign); + PSBTInput psbtInput = psbt.getPsbtInputs().get(0); + psbtInput.setWitnessUtxo(toSpend.getOutputs().get(0)); + psbtInput.setSigHash(SigHash.ALL); + + if(address.getScriptType() == ScriptType.P2WPKH) { + psbtInput.getPartialSignatures().put(pubKey, signature); + } else if(address.getScriptType() == ScriptType.P2TR) { + psbtInput.setTapKeyPathSignature(signature); + } + + try { + psbt.verifySignatures(); + } catch(PSBTSignatureException e) { + throw new SignatureException("Signature did not match for message", e); + } + } + + public static Transaction getBip322ToSpend(Address address, String message) { + Transaction toSpend = new Transaction(); + toSpend.setVersion(0); + toSpend.setLocktime(0); + + List scriptSigChunks = new ArrayList<>(); + scriptSigChunks.add(ScriptChunk.fromOpcode(ScriptOpCodes.OP_0)); + scriptSigChunks.add(ScriptChunk.fromData(getBip322MessageHash(message))); + Script scriptSig = new Script(scriptSigChunks); + toSpend.addInput(Sha256Hash.ZERO_HASH, 0xFFFFFFFFL, scriptSig, new TransactionWitness(toSpend, Collections.emptyList())); + toSpend.getInputs().get(0).setSequenceNumber(0L); + toSpend.addOutput(0L, address.getOutputScript()); + + return toSpend; + } + + public static Transaction getBip322ToSign(Transaction toSpend) { + Transaction toSign = new Transaction(); + toSign.setVersion(0); + toSign.setLocktime(0); + + TransactionWitness witness = new TransactionWitness(toSign); + toSign.addInput(toSpend.getTxId(), 0L, new Script(new byte[0]), witness); + toSign.getInputs().get(0).setSequenceNumber(0L); + toSign.addOutput(0, new Script(List.of(ScriptChunk.fromOpcode(ScriptOpCodes.OP_RETURN)))); + + return toSign; + } + + public static byte[] getBip322MessageHash(String message) { + if(message == null) { + throw new IllegalArgumentException("Message cannot be null"); + } + + return Utils.taggedHash("BIP0322-signed-message", message.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/TransactionSignature.java b/src/main/java/com/sparrowwallet/drongo/protocol/TransactionSignature.java index e9b173e..15e3299 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/TransactionSignature.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/TransactionSignature.java @@ -103,7 +103,7 @@ public class TransactionSignature { } public static TransactionSignature decodeFromBitcoin(byte[] bytes, boolean requireCanonicalEncoding) throws SignatureDecodeException { - if(bytes.length == 64) { + if(bytes.length == 64 || bytes.length == 65) { return decodeFromBitcoin(Type.SCHNORR, bytes, requireCanonicalEncoding); } diff --git a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java new file mode 100644 index 0000000..2201964 --- /dev/null +++ b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java @@ -0,0 +1,118 @@ +package com.sparrowwallet.drongo.crypto; + +import com.sparrowwallet.drongo.Utils; +import com.sparrowwallet.drongo.address.Address; +import com.sparrowwallet.drongo.address.InvalidAddressException; +import com.sparrowwallet.drongo.protocol.ScriptType; +import com.sparrowwallet.drongo.protocol.Sha256Hash; +import com.sparrowwallet.drongo.protocol.SigHash; +import com.sparrowwallet.drongo.protocol.TransactionSignature; +import com.sparrowwallet.drongo.psbt.PSBTInputSigner; +import org.junit.Assert; +import org.junit.Test; + +import java.security.SignatureException; + +public class Bip322Test { + @Test + public void getBip322TaggedHash() { + byte[] empty = Bip322.getBip322MessageHash(""); + Assert.assertArrayEquals(Utils.hexToBytes("c90c269c4f8fcbe6880f72a721ddfbf1914268a794cbb21cfafee13770ae19f1"), empty); + + byte[] hello = Bip322.getBip322MessageHash("Hello World"); + Assert.assertArrayEquals(Utils.hexToBytes("f0eb03b1a75ac6d9847f55c624a99169b5dccba2a31f5b23bea77ba270de0a7a"), hello); + } + + @Test + public void signMessageBip322() { + ECKey privKey = DumpedPrivateKey.fromBase58("L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k").getKey(); + Address address = ScriptType.P2WPKH.getAddress(privKey); + Assert.assertEquals("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l", address.toString()); + + String signature = Bip322.signMessageBip322(address, "", new PSBTInputSigner() { + @Override + public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { + return privKey.sign(hash, sigHash, signatureType); + } + + @Override + public ECKey getPubKey() { + return ECKey.fromPublicOnly(privKey); + } + }); + + Assert.assertEquals("AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature); + + String signature2 = Bip322.signMessageBip322(address, "Hello World", new PSBTInputSigner() { + @Override + public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { + return privKey.sign(hash, sigHash, signatureType); + } + + @Override + public ECKey getPubKey() { + return ECKey.fromPublicOnly(privKey); + } + }); + + Assert.assertEquals("AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature2); + } + + @Test(expected = SignatureException.class) + public void verifyMessageBip322Fail() throws InvalidAddressException, SignatureException { + Address address = Address.fromString("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l"); + String message1 = ""; + String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; + + Bip322.verifyMessageBip322(address, message1, signature2); + } + + @Test + public void verifyMessageBip322() throws InvalidAddressException, SignatureException { + Address address = Address.fromString("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l"); + String message1 = ""; + String signature1 = "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; + + Bip322.verifyMessageBip322(address, message1, signature1); + + String message2 = "Hello World"; + String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; + Bip322.verifyMessageBip322(address, message2, signature2); + + String signature3 = "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy"; + Bip322.verifyMessageBip322(address, message2, signature3); + } + + @Test + public void signMessageBip322Taproot() { + ECKey privKey = DumpedPrivateKey.fromBase58("L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k").getKey(); + Address address = ScriptType.P2TR.getAddress(privKey); + Assert.assertEquals("bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3", address.toString()); + + String signature = Bip322.signMessageBip322(address, "Hello World", new PSBTInputSigner() { + @Override + public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { + return address.getScriptType().getOutputKey(privKey).sign(hash, sigHash, signatureType); + } + + @Override + public ECKey getPubKey() { + return ECKey.fromPublicOnly(privKey); + } + }); + + Assert.assertEquals("AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ==", signature); + } + + @Test + public void verifyMessageBip322Taproot() throws SignatureException { + ECKey privKey = DumpedPrivateKey.fromBase58("L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k").getKey(); + Address address = ScriptType.P2TR.getAddress(privKey); + Assert.assertEquals("bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3", address.toString()); + + String message1 = "Hello World"; + String signature1 = "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ=="; + + Bip322.verifyMessageBip322(address, message1, signature1); + } +} From e965a9ddd73257a97c68b44bc73160aa68fe47f7 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Mon, 3 Jul 2023 13:15:10 +0200 Subject: [PATCH 24/31] add script type checks to bip322 implementation --- .../sparrowwallet/drongo/crypto/Bip322.java | 37 ++++++++++---- .../drongo/crypto/Bip322Test.java | 49 ++++++++++++++++--- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java index c6a3304..1919df7 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -2,6 +2,7 @@ package com.sparrowwallet.drongo.crypto; import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.address.Address; +import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.psbt.PSBT; import com.sparrowwallet.drongo.psbt.PSBTInput; @@ -15,7 +16,9 @@ import java.util.*; import static com.sparrowwallet.drongo.protocol.ScriptType.P2TR; public class Bip322 { - public static String signMessageBip322(Address address, String message, PSBTInputSigner psbtInputSigner) { + public static String signMessageBip322(ScriptType scriptType, Address address, String message, PSBTInputSigner psbtInputSigner) { + checkScriptType(scriptType); + Transaction toSpend = getBip322ToSpend(address, message); Transaction toSign = getBip322ToSign(toSpend); @@ -31,12 +34,14 @@ public class Bip322 { TransactionSignature signature = psbtInput.isTaproot() ? psbtInput.getTapKeyPathSignature() : psbtInput.getPartialSignature(pubKey); Transaction finalizeTransaction = new Transaction(); - TransactionInput finalizedTxInput = address.getScriptType().addSpendingInput(finalizeTransaction, utxoOutput, pubKey, signature); + TransactionInput finalizedTxInput = scriptType.addSpendingInput(finalizeTransaction, utxoOutput, pubKey, signature); return Base64.getEncoder().encodeToString(finalizedTxInput.getWitness().toByteArray()); } - public static void verifyMessageBip322(Address address, String message, String signatureBase64) throws SignatureException { + public static void verifyMessageBip322(ScriptType scriptType, Address address, String message, String signatureBase64) throws SignatureException { + checkScriptType(scriptType); + byte[] signatureEncoded; try { signatureEncoded = Base64.getDecoder().decode(signatureBase64); @@ -52,14 +57,14 @@ public class Bip322 { signature = witness.getSignatures().get(0); pubKey = ECKey.fromPublicOnly(witness.getPushes().get(1)); - if(!address.equals(address.getScriptType().getAddress(pubKey))) { + if(!address.equals(scriptType.getAddress(pubKey))) { throw new SignatureException("Provided address does not match pubkey in signature"); } - } else if(address.getScriptType() == ScriptType.P2TR) { + } else if(scriptType == ScriptType.P2TR) { signature = witness.getSignatures().get(0); pubKey = P2TR.getPublicKeyFromScript(address.getOutputScript()); } else { - throw new IllegalArgumentException(address.getScriptType() + " addresses are not supported"); + throw new IllegalArgumentException(scriptType + " addresses are not supported"); } Transaction toSpend = getBip322ToSpend(address, message); @@ -70,10 +75,10 @@ public class Bip322 { psbtInput.setWitnessUtxo(toSpend.getOutputs().get(0)); psbtInput.setSigHash(SigHash.ALL); - if(address.getScriptType() == ScriptType.P2WPKH) { - psbtInput.getPartialSignatures().put(pubKey, signature); - } else if(address.getScriptType() == ScriptType.P2TR) { + if(scriptType == ScriptType.P2TR) { psbtInput.setTapKeyPathSignature(signature); + } else { + psbtInput.getPartialSignatures().put(pubKey, signature); } try { @@ -83,6 +88,20 @@ public class Bip322 { } } + private static void checkScriptType(ScriptType scriptType) { + if(!scriptType.isAllowed(PolicyType.SINGLE)) { + throw new UnsupportedOperationException("Only singlesig addresses are currently supported"); + } + + if(!Arrays.asList(ScriptType.WITNESS_TYPES).contains(scriptType)) { + throw new UnsupportedOperationException("Legacy addresses are not supported for BIP322 simple signatures"); + } + + if(scriptType == ScriptType.P2SH_P2WPKH) { + throw new UnsupportedOperationException("The P2SH-P2WPKH script type is not currently supported"); + } + } + public static Transaction getBip322ToSpend(Address address, String message) { Transaction toSpend = new Transaction(); toSpend.setVersion(0); diff --git a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java index 2201964..9f0d4ae 100644 --- a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java +++ b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java @@ -29,7 +29,7 @@ public class Bip322Test { Address address = ScriptType.P2WPKH.getAddress(privKey); Assert.assertEquals("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l", address.toString()); - String signature = Bip322.signMessageBip322(address, "", new PSBTInputSigner() { + String signature = Bip322.signMessageBip322(ScriptType.P2WPKH, address, "", new PSBTInputSigner() { @Override public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { return privKey.sign(hash, sigHash, signatureType); @@ -43,7 +43,7 @@ public class Bip322Test { Assert.assertEquals("AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature); - String signature2 = Bip322.signMessageBip322(address, "Hello World", new PSBTInputSigner() { + String signature2 = Bip322.signMessageBip322(ScriptType.P2WPKH, address, "Hello World", new PSBTInputSigner() { @Override public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { return privKey.sign(hash, sigHash, signatureType); @@ -64,7 +64,7 @@ public class Bip322Test { String message1 = ""; String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(address, message1, signature2); + Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature2); } @Test @@ -73,14 +73,14 @@ public class Bip322Test { String message1 = ""; String signature1 = "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(address, message1, signature1); + Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature1); String message2 = "Hello World"; String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(address, message2, signature2); + Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature2); String signature3 = "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy"; - Bip322.verifyMessageBip322(address, message2, signature3); + Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature3); } @Test @@ -89,7 +89,7 @@ public class Bip322Test { Address address = ScriptType.P2TR.getAddress(privKey); Assert.assertEquals("bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3", address.toString()); - String signature = Bip322.signMessageBip322(address, "Hello World", new PSBTInputSigner() { + String signature = Bip322.signMessageBip322(ScriptType.P2TR, address, "Hello World", new PSBTInputSigner() { @Override public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { return address.getScriptType().getOutputKey(privKey).sign(hash, sigHash, signatureType); @@ -113,6 +113,39 @@ public class Bip322Test { String message1 = "Hello World"; String signature1 = "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ=="; - Bip322.verifyMessageBip322(address, message1, signature1); + Bip322.verifyMessageBip322(ScriptType.P2TR, address, message1, signature1); + } + + @Test(expected = UnsupportedOperationException.class) + public void signMessageBip322NestedSegwit() { + ECKey privKey = DumpedPrivateKey.fromBase58("L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k").getKey(); + Address address = ScriptType.P2SH_P2WPKH.getAddress(privKey); + Assert.assertEquals("37qyp7jQAzqb2rCBpMvVtLDuuzKAUCVnJb", address.toString()); + + String signature = Bip322.signMessageBip322(ScriptType.P2SH_P2WPKH, address, "Hello World", new PSBTInputSigner() { + @Override + public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { + return address.getScriptType().getOutputKey(privKey).sign(hash, sigHash, signatureType); + } + + @Override + public ECKey getPubKey() { + return ECKey.fromPublicOnly(privKey); + } + }); + + Assert.assertEquals("AkcwRAIgHx821fcP3D4R6RsXHF8kXza4d/SqpKGaGu++AEQjJz0CIH9cN5XGDkgkqqF9OMTbYvhgI7Yp9NoHXEgLstjqDOqDASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature); + } + + @Test(expected = UnsupportedOperationException.class) + public void verifyMessageBip322NestedSegwit() throws SignatureException { + ECKey privKey = DumpedPrivateKey.fromBase58("L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k").getKey(); + Address address = ScriptType.P2SH_P2WPKH.getAddress(privKey); + Assert.assertEquals("37qyp7jQAzqb2rCBpMvVtLDuuzKAUCVnJb", address.toString()); + + String message1 = "Hello World"; + String signature1 = "AkcwRAIgHx821fcP3D4R6RsXHF8kXza4d/SqpKGaGu++AEQjJz0CIH9cN5XGDkgkqqF9OMTbYvhgI7Yp9NoHXEgLstjqDOqDASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; + + Bip322.verifyMessageBip322(ScriptType.P2SH_P2WPKH, address, message1, signature1); } } From f47d5de3922a88ae385e586dcc3947f05c2ae803 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 4 Jul 2023 08:50:49 +0200 Subject: [PATCH 25/31] minor refactor of bip322 implementation --- .../sparrowwallet/drongo/crypto/Bip322.java | 10 ++-- .../drongo/crypto/Bip322Test.java | 56 ++----------------- 2 files changed, 10 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java index 1919df7..3b40c56 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -16,9 +16,12 @@ import java.util.*; import static com.sparrowwallet.drongo.protocol.ScriptType.P2TR; public class Bip322 { - public static String signMessageBip322(ScriptType scriptType, Address address, String message, PSBTInputSigner psbtInputSigner) { + public static String signMessageBip322(ScriptType scriptType, String message, ECKey privKey) { checkScriptType(scriptType); + ECKey pubKey = ECKey.fromPublicOnly(privKey); + Address address = scriptType.getAddress(pubKey); + Transaction toSpend = getBip322ToSpend(address, message); Transaction toSign = getBip322ToSign(toSpend); @@ -28,9 +31,8 @@ public class Bip322 { PSBTInput psbtInput = psbt.getPsbtInputs().get(0); psbtInput.setWitnessUtxo(utxoOutput); psbtInput.setSigHash(SigHash.ALL); - psbtInput.sign(psbtInputSigner); + psbtInput.sign(scriptType.getOutputKey(privKey)); - ECKey pubKey = psbtInputSigner.getPubKey(); TransactionSignature signature = psbtInput.isTaproot() ? psbtInput.getTapKeyPathSignature() : psbtInput.getPartialSignature(pubKey); Transaction finalizeTransaction = new Transaction(); @@ -53,7 +55,7 @@ public class Bip322 { TransactionSignature signature; ECKey pubKey; - if(address.getScriptType() == ScriptType.P2WPKH) { + if(scriptType == ScriptType.P2WPKH) { signature = witness.getSignatures().get(0); pubKey = ECKey.fromPublicOnly(witness.getPushes().get(1)); diff --git a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java index 9f0d4ae..cd6295a 100644 --- a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java +++ b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java @@ -4,10 +4,6 @@ import com.sparrowwallet.drongo.Utils; import com.sparrowwallet.drongo.address.Address; import com.sparrowwallet.drongo.address.InvalidAddressException; import com.sparrowwallet.drongo.protocol.ScriptType; -import com.sparrowwallet.drongo.protocol.Sha256Hash; -import com.sparrowwallet.drongo.protocol.SigHash; -import com.sparrowwallet.drongo.protocol.TransactionSignature; -import com.sparrowwallet.drongo.psbt.PSBTInputSigner; import org.junit.Assert; import org.junit.Test; @@ -29,32 +25,10 @@ public class Bip322Test { Address address = ScriptType.P2WPKH.getAddress(privKey); Assert.assertEquals("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l", address.toString()); - String signature = Bip322.signMessageBip322(ScriptType.P2WPKH, address, "", new PSBTInputSigner() { - @Override - public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { - return privKey.sign(hash, sigHash, signatureType); - } - - @Override - public ECKey getPubKey() { - return ECKey.fromPublicOnly(privKey); - } - }); - + String signature = Bip322.signMessageBip322(ScriptType.P2WPKH, "", privKey); Assert.assertEquals("AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature); - String signature2 = Bip322.signMessageBip322(ScriptType.P2WPKH, address, "Hello World", new PSBTInputSigner() { - @Override - public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { - return privKey.sign(hash, sigHash, signatureType); - } - - @Override - public ECKey getPubKey() { - return ECKey.fromPublicOnly(privKey); - } - }); - + String signature2 = Bip322.signMessageBip322(ScriptType.P2WPKH, "Hello World", privKey); Assert.assertEquals("AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature2); } @@ -89,18 +63,7 @@ public class Bip322Test { Address address = ScriptType.P2TR.getAddress(privKey); Assert.assertEquals("bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3", address.toString()); - String signature = Bip322.signMessageBip322(ScriptType.P2TR, address, "Hello World", new PSBTInputSigner() { - @Override - public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { - return address.getScriptType().getOutputKey(privKey).sign(hash, sigHash, signatureType); - } - - @Override - public ECKey getPubKey() { - return ECKey.fromPublicOnly(privKey); - } - }); - + String signature = Bip322.signMessageBip322(ScriptType.P2TR, "Hello World", privKey); Assert.assertEquals("AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ==", signature); } @@ -122,18 +85,7 @@ public class Bip322Test { Address address = ScriptType.P2SH_P2WPKH.getAddress(privKey); Assert.assertEquals("37qyp7jQAzqb2rCBpMvVtLDuuzKAUCVnJb", address.toString()); - String signature = Bip322.signMessageBip322(ScriptType.P2SH_P2WPKH, address, "Hello World", new PSBTInputSigner() { - @Override - public TransactionSignature sign(Sha256Hash hash, SigHash sigHash, TransactionSignature.Type signatureType) { - return address.getScriptType().getOutputKey(privKey).sign(hash, sigHash, signatureType); - } - - @Override - public ECKey getPubKey() { - return ECKey.fromPublicOnly(privKey); - } - }); - + String signature = Bip322.signMessageBip322(ScriptType.P2SH_P2WPKH, "Hello World", privKey); Assert.assertEquals("AkcwRAIgHx821fcP3D4R6RsXHF8kXza4d/SqpKGaGu++AEQjJz0CIH9cN5XGDkgkqqF9OMTbYvhgI7Yp9NoHXEgLstjqDOqDASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature); } From 6a7d2aac285e9300b5897d1b64d0e5baa25e428d Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 4 Jul 2023 09:21:48 +0200 Subject: [PATCH 26/31] throw exception for bip322 multisig signatures --- .../sparrowwallet/drongo/crypto/Bip322.java | 16 +++++++++++--- .../drongo/crypto/Bip322Test.java | 22 ++++++++++++++----- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java index 3b40c56..5d38427 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -41,7 +41,7 @@ public class Bip322 { return Base64.getEncoder().encodeToString(finalizedTxInput.getWitness().toByteArray()); } - public static void verifyMessageBip322(ScriptType scriptType, Address address, String message, String signatureBase64) throws SignatureException { + public static boolean verifyMessageBip322(ScriptType scriptType, Address address, String message, String signatureBase64) throws SignatureException { checkScriptType(scriptType); byte[] signatureEncoded; @@ -55,6 +55,10 @@ public class Bip322 { TransactionSignature signature; ECKey pubKey; + if(witness.getWitnessScript() != null) { + throw new IllegalArgumentException("Multisig signatures are not supported."); + } + if(scriptType == ScriptType.P2WPKH) { signature = witness.getSignatures().get(0); pubKey = ECKey.fromPublicOnly(witness.getPushes().get(1)); @@ -66,7 +70,7 @@ public class Bip322 { signature = witness.getSignatures().get(0); pubKey = P2TR.getPublicKeyFromScript(address.getOutputScript()); } else { - throw new IllegalArgumentException(scriptType + " addresses are not supported"); + throw new SignatureException(scriptType + " addresses are not supported"); } Transaction toSpend = getBip322ToSpend(address, message); @@ -86,8 +90,10 @@ public class Bip322 { try { psbt.verifySignatures(); } catch(PSBTSignatureException e) { - throw new SignatureException("Signature did not match for message", e); + return false; } + + return true; } private static void checkScriptType(ScriptType scriptType) { @@ -104,6 +110,10 @@ public class Bip322 { } } + public static boolean isSupported(ScriptType scriptType) { + return scriptType == ScriptType.P2WPKH || scriptType == P2TR; + } + public static Transaction getBip322ToSpend(Address address, String message) { Transaction toSpend = new Transaction(); toSpend.setVersion(0); diff --git a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java index cd6295a..9124a66 100644 --- a/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java +++ b/src/test/java/com/sparrowwallet/drongo/crypto/Bip322Test.java @@ -32,13 +32,13 @@ public class Bip322Test { Assert.assertEquals("AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=", signature2); } - @Test(expected = SignatureException.class) + @Test public void verifyMessageBip322Fail() throws InvalidAddressException, SignatureException { Address address = Address.fromString("bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l"); String message1 = ""; String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature2); + Assert.assertFalse(Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature2)); } @Test @@ -47,14 +47,14 @@ public class Bip322Test { String message1 = ""; String signature1 = "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature1); + Assert.assertTrue(Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message1, signature1)); String message2 = "Hello World"; String signature2 = "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="; - Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature2); + Assert.assertTrue(Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature2)); String signature3 = "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy"; - Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature3); + Assert.assertTrue(Bip322.verifyMessageBip322(ScriptType.P2WPKH, address, message2, signature3)); } @Test @@ -76,7 +76,7 @@ public class Bip322Test { String message1 = "Hello World"; String signature1 = "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ=="; - Bip322.verifyMessageBip322(ScriptType.P2TR, address, message1, signature1); + Assert.assertTrue(Bip322.verifyMessageBip322(ScriptType.P2TR, address, message1, signature1)); } @Test(expected = UnsupportedOperationException.class) @@ -100,4 +100,14 @@ public class Bip322Test { Bip322.verifyMessageBip322(ScriptType.P2SH_P2WPKH, address, message1, signature1); } + + @Test(expected = IllegalArgumentException.class) + public void verifyMessageBip322Multisig() throws SignatureException, InvalidAddressException { + Address address = Address.fromString("bc1ppv609nr0vr25u07u95waq5lucwfm6tde4nydujnu8npg4q75mr5sxq8lt3"); + + String message1 = "This will be a p2wsh 3-of-3 multisig BIP 322 signed message"; + String signature1 = "BQBIMEUCIQDQoXvGKLH58exuujBOta+7+GN7vi0lKwiQxzBpuNuXuAIgIE0XYQlFDOfxbegGYYzlf+tqegleAKE6SXYIa1U+uCcBRzBEAiATegywVl6GWrG9jJuPpNwtgHKyVYCX2yfuSSDRFATAaQIgTLlU6reLQsSIrQSF21z3PtUO2yAUseUWGZqRUIE7VKoBSDBFAiEAgxtpidsU0Z4u/+5RB9cyeQtoCW5NcreLJmWXZ8kXCZMCIBR1sXoEinhZE4CF9P9STGIcMvCuZjY6F5F0XTVLj9SjAWlTIQP3dyWvTZjUENWJowMWBsQrrXCUs20Gu5YF79CG5Ga0XSEDwqI5GVBOuFkFzQOGH5eTExSAj2Z/LDV/hbcvAPQdlJMhA17FuuJd+4wGuj+ZbVxEsFapTKAOwyhfw9qpch52JKxbU64="; + + Bip322.verifyMessageBip322(ScriptType.P2TR, address, message1, signature1); + } } From 8484dd397b95d200cf3c363cd48e5751550b3bcb Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 11 Jul 2023 09:07:22 +0200 Subject: [PATCH 27/31] use txo filters for all wallet transaction output filtering --- ...UtxoFilter.java => CoinbaseTxoFilter.java} | 4 +- .../drongo/wallet/ExcludeTxoFilter.java | 31 +++++++++ .../drongo/wallet/ExcludeUtxoFilter.java | 31 --------- ...enUtxoFilter.java => FrozenTxoFilter.java} | 2 +- .../drongo/wallet/PresetUtxoSelector.java | 14 ++-- .../drongo/wallet/SpentTxoFilter.java | 24 +++++++ .../{UtxoFilter.java => TxoFilter.java} | 2 +- .../sparrowwallet/drongo/wallet/Wallet.java | 67 ++++++++++--------- .../drongo/wallet/WalletNode.java | 6 +- 9 files changed, 106 insertions(+), 75 deletions(-) rename src/main/java/com/sparrowwallet/drongo/wallet/{CoinbaseUtxoFilter.java => CoinbaseTxoFilter.java} (87%) create mode 100644 src/main/java/com/sparrowwallet/drongo/wallet/ExcludeTxoFilter.java delete mode 100644 src/main/java/com/sparrowwallet/drongo/wallet/ExcludeUtxoFilter.java rename src/main/java/com/sparrowwallet/drongo/wallet/{FrozenUtxoFilter.java => FrozenTxoFilter.java} (80%) create mode 100644 src/main/java/com/sparrowwallet/drongo/wallet/SpentTxoFilter.java rename src/main/java/com/sparrowwallet/drongo/wallet/{UtxoFilter.java => TxoFilter.java} (77%) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseUtxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseTxoFilter.java similarity index 87% rename from src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseUtxoFilter.java rename to src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseTxoFilter.java index 8f079f6..6c0e03c 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseUtxoFilter.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/CoinbaseTxoFilter.java @@ -2,10 +2,10 @@ package com.sparrowwallet.drongo.wallet; import com.sparrowwallet.drongo.protocol.Transaction; -public class CoinbaseUtxoFilter implements UtxoFilter { +public class CoinbaseTxoFilter implements TxoFilter { private final Wallet wallet; - public CoinbaseUtxoFilter(Wallet wallet) { + public CoinbaseTxoFilter(Wallet wallet) { this.wallet = wallet; } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeTxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeTxoFilter.java new file mode 100644 index 0000000..e92837c --- /dev/null +++ b/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeTxoFilter.java @@ -0,0 +1,31 @@ +package com.sparrowwallet.drongo.wallet; + +import java.util.ArrayList; +import java.util.Collection; + +public class ExcludeTxoFilter implements TxoFilter { + private final Collection excludedTxos; + + public ExcludeTxoFilter() { + this.excludedTxos = new ArrayList<>(); + } + + public ExcludeTxoFilter(Collection excludedTxos) { + this.excludedTxos = new ArrayList<>(excludedTxos); + } + + @Override + public boolean isEligible(BlockTransactionHashIndex candidate) { + for(BlockTransactionHashIndex excludedTxo : excludedTxos) { + if(candidate.getHash().equals(excludedTxo.getHash()) && candidate.getIndex() == excludedTxo.getIndex()) { + return false; + } + } + + return true; + } + + public Collection getExcludedTxos() { + return excludedTxos; + } +} diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeUtxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeUtxoFilter.java deleted file mode 100644 index f87ae7d..0000000 --- a/src/main/java/com/sparrowwallet/drongo/wallet/ExcludeUtxoFilter.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.sparrowwallet.drongo.wallet; - -import java.util.ArrayList; -import java.util.Collection; - -public class ExcludeUtxoFilter implements UtxoFilter { - private final Collection excludedUtxos; - - public ExcludeUtxoFilter() { - this.excludedUtxos = new ArrayList<>(); - } - - public ExcludeUtxoFilter(Collection excludedUtxos) { - this.excludedUtxos = new ArrayList<>(excludedUtxos); - } - - @Override - public boolean isEligible(BlockTransactionHashIndex candidate) { - for(BlockTransactionHashIndex excludedUtxo : excludedUtxos) { - if(candidate.getHash().equals(excludedUtxo.getHash()) && candidate.getIndex() == excludedUtxo.getIndex()) { - return false; - } - } - - return true; - } - - public Collection getExcludedUtxos() { - return excludedUtxos; - } -} diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/FrozenUtxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/FrozenTxoFilter.java similarity index 80% rename from src/main/java/com/sparrowwallet/drongo/wallet/FrozenUtxoFilter.java rename to src/main/java/com/sparrowwallet/drongo/wallet/FrozenTxoFilter.java index 6b61dbc..3b50b74 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/FrozenUtxoFilter.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/FrozenTxoFilter.java @@ -1,6 +1,6 @@ package com.sparrowwallet.drongo.wallet; -public class FrozenUtxoFilter implements UtxoFilter { +public class FrozenTxoFilter implements TxoFilter { @Override public boolean isEligible(BlockTransactionHashIndex candidate) { return candidate.getStatus() == null || candidate.getStatus() != Status.FROZEN; diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java index 996fd17..85f4608 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java @@ -1,14 +1,13 @@ package com.sparrowwallet.drongo.wallet; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; public class PresetUtxoSelector extends SingleSetUtxoSelector { private final Collection presetUtxos; private final Collection excludedUtxos; private final boolean maintainOrder; + private final boolean requireAll; public PresetUtxoSelector(Collection presetUtxos) { this(presetUtxos, new ArrayList<>()); @@ -18,12 +17,14 @@ public class PresetUtxoSelector extends SingleSetUtxoSelector { this.presetUtxos = presetUtxos; this.excludedUtxos = excludedUtxos; this.maintainOrder = false; + this.requireAll = false; } - public PresetUtxoSelector(Collection presetUtxos, boolean maintainOrder) { + public PresetUtxoSelector(Collection presetUtxos, boolean maintainOrder, boolean requireAll) { this.presetUtxos = presetUtxos; this.excludedUtxos = new ArrayList<>(); this.maintainOrder = maintainOrder; + this.requireAll = requireAll; } @Override @@ -40,8 +41,11 @@ public class PresetUtxoSelector extends SingleSetUtxoSelector { } } - if(maintainOrder && utxos.containsAll(presetUtxos)) { + Set utxosSet = new HashSet<>(utxos); + if(maintainOrder && utxosSet.containsAll(presetUtxos)) { return presetUtxos; + } else if(requireAll && !utxosSet.containsAll(presetUtxos)) { + return Collections.emptyList(); } return utxos; diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/SpentTxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/SpentTxoFilter.java new file mode 100644 index 0000000..6d882e1 --- /dev/null +++ b/src/main/java/com/sparrowwallet/drongo/wallet/SpentTxoFilter.java @@ -0,0 +1,24 @@ +package com.sparrowwallet.drongo.wallet; + +import com.sparrowwallet.drongo.protocol.Sha256Hash; + +public class SpentTxoFilter implements TxoFilter { + private final Sha256Hash replacedTxid; + + public SpentTxoFilter() { + replacedTxid = null; + } + + public SpentTxoFilter(Sha256Hash replacedTxid) { + this.replacedTxid = replacedTxid; + } + + @Override + public boolean isEligible(BlockTransactionHashIndex candidate) { + return !isSpentOrReplaced(candidate); + } + + private boolean isSpentOrReplaced(BlockTransactionHashIndex candidate) { + return candidate.getHash().equals(replacedTxid) || (candidate.isSpent() && !candidate.getSpentBy().getHash().equals(replacedTxid)); + } +} diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/UtxoFilter.java b/src/main/java/com/sparrowwallet/drongo/wallet/TxoFilter.java similarity index 77% rename from src/main/java/com/sparrowwallet/drongo/wallet/UtxoFilter.java rename to src/main/java/com/sparrowwallet/drongo/wallet/TxoFilter.java index 5b2a6f8..36bd051 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/UtxoFilter.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/TxoFilter.java @@ -1,5 +1,5 @@ package com.sparrowwallet.drongo.wallet; -public interface UtxoFilter { +public interface TxoFilter { boolean isEligible(BlockTransactionHashIndex candidate); } diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 267d493..8551ca4 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -799,30 +799,38 @@ public class Wallet extends Persistable implements Comparable { } public Map getWalletUtxos() { - return getWalletUtxos(false); + return getWalletTxos(List.of(new SpentTxoFilter())); } - public Map getWalletUtxos(boolean includeSpentMempoolOutputs) { - Map walletUtxos = new TreeMap<>(); + public Map getSpendableUtxos() { + return getWalletTxos(List.of(new SpentTxoFilter(), new FrozenTxoFilter(), new CoinbaseTxoFilter(this))); + } + + public Map getSpendableUtxos(BlockTransaction replacedTransaction) { + return getWalletTxos(List.of(new SpentTxoFilter(replacedTransaction == null ? null : replacedTransaction.getHash()), new FrozenTxoFilter(), new CoinbaseTxoFilter(this))); + } + + public Map getWalletTxos(Collection txoFilters) { + Map walletTxos = new TreeMap<>(); for(KeyPurpose keyPurpose : getWalletKeyPurposes()) { - getWalletUtxos(walletUtxos, getNode(keyPurpose), includeSpentMempoolOutputs); + getWalletTxos(walletTxos, getNode(keyPurpose), txoFilters); } for(Wallet childWallet : getChildWallets()) { if(childWallet.isNested()) { for(KeyPurpose keyPurpose : childWallet.getWalletKeyPurposes()) { - getWalletUtxos(walletUtxos, childWallet.getNode(keyPurpose), includeSpentMempoolOutputs); + getWalletTxos(walletTxos, childWallet.getNode(keyPurpose), txoFilters); } } } - return walletUtxos; + return walletTxos; } - private void getWalletUtxos(Map walletUtxos, WalletNode purposeNode, boolean includeSpentMempoolOutputs) { + private void getWalletTxos(Map walletTxos, WalletNode purposeNode, Collection txoFilters) { for(WalletNode addressNode : purposeNode.getChildren()) { - for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs(includeSpentMempoolOutputs)) { - walletUtxos.put(utxo, addressNode); + for(BlockTransactionHashIndex utxo : addressNode.getTransactionOutputs(txoFilters)) { + walletTxos.put(utxo, addressNode); } } } @@ -981,29 +989,30 @@ public class Wallet extends Persistable implements Comparable { return getFee(changeOutput, feeRate, longTermFeeRate); } - public WalletTransaction createWalletTransaction(List utxoSelectors, List utxoFilters, List payments, List opReturns, Set excludedChangeNodes, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs) throws InsufficientFundsException { + public WalletTransaction createWalletTransaction(List utxoSelectors, List txoFilters, List payments, List opReturns, Set excludedChangeNodes, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolOutputs) throws InsufficientFundsException { boolean sendMax = payments.stream().anyMatch(Payment::isSendMax); long totalPaymentAmount = payments.stream().map(Payment::getAmount).mapToLong(v -> v).sum(); - long totalUtxoValue = getWalletUtxos().keySet().stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); + Map availableTxos = getWalletTxos(txoFilters); + long totalAvailableValue = availableTxos.keySet().stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); if(fee != null && feeRate != Transaction.DEFAULT_MIN_RELAY_FEE) { throw new IllegalArgumentException("Use an input fee rate of 1 sat/vB when using a defined fee amount so UTXO selectors overestimate effective value"); } - long maxSpendableAmt = getMaxSpendable(payments.stream().map(Payment::getAddress).collect(Collectors.toList()), feeRate, includeSpentMempoolOutputs); + long maxSpendableAmt = getMaxSpendable(payments.stream().map(Payment::getAddress).collect(Collectors.toList()), feeRate, availableTxos); if(maxSpendableAmt < 0) { throw new InsufficientFundsException("Not enough combined value in all available UTXOs to send a transaction to the provided addresses at this fee rate"); } //When a user fee is set, we can calculate the fees to spend all UTXOs because we assume all UTXOs are spendable at a fee rate of 1 sat/vB //We can then add the user set fee less this amount as a "phantom payment amount" to the value required to find (which cannot include transaction fees) - long valueRequiredAmt = totalPaymentAmount + (fee != null ? fee - (totalUtxoValue - maxSpendableAmt) : 0); + long valueRequiredAmt = totalPaymentAmount + (fee != null ? fee - (totalAvailableValue - maxSpendableAmt) : 0); if(maxSpendableAmt < valueRequiredAmt) { throw new InsufficientFundsException("Not enough combined value in all available UTXOs to send a transaction to send the provided payments at the user set fee" + (fee == null ? " rate" : "")); } while(true) { - List> selectedUtxoSets = selectInputSets(utxoSelectors, utxoFilters, valueRequiredAmt, feeRate, longTermFeeRate, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs, sendMax); + List> selectedUtxoSets = selectInputSets(availableTxos, utxoSelectors, txoFilters, valueRequiredAmt, feeRate, longTermFeeRate, groupByAddress, includeMempoolOutputs, sendMax); Map selectedUtxos = new LinkedHashMap<>(); selectedUtxoSets.forEach(selectedUtxos::putAll); long totalSelectedAmt = selectedUtxos.keySet().stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); @@ -1076,8 +1085,8 @@ public class Wallet extends Persistable implements Comparable { if(differenceAmt < noChangeFeeRequiredAmt) { valueRequiredAmt = totalSelectedAmt + 1; //If we haven't selected all UTXOs yet, don't require more than the max spendable amount - if(valueRequiredAmt > maxSpendableAmt && transaction.getInputs().size() < getWalletUtxos().size()) { - valueRequiredAmt = maxSpendableAmt; + if(valueRequiredAmt > maxSpendableAmt && transaction.getInputs().size() < availableTxos.size()) { + valueRequiredAmt = maxSpendableAmt; } continue; @@ -1180,8 +1189,8 @@ public class Wallet extends Persistable implements Comparable { } } - private List> selectInputSets(List utxoSelectors, List utxoFilters, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolOutputs, boolean includeSpentMempoolOutputs, boolean sendMax) throws InsufficientFundsException { - List utxoPool = getGroupedUtxos(utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); + private List> selectInputSets(Map availableTxos, List utxoSelectors, List txoFilters, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolOutputs, boolean sendMax) throws InsufficientFundsException { + List utxoPool = getGroupedUtxos(txoFilters, feeRate, longTermFeeRate, groupByAddress); List filters = new ArrayList<>(); filters.add(new OutputGroup.Filter(1, 6, false)); @@ -1204,7 +1213,6 @@ public class Wallet extends Persistable implements Comparable { List> selectedInputSets = utxoSelector.selectSets(targetValue, filteredPool); List> selectedInputSetsList = new ArrayList<>(); long total = 0; - Map utxos = getWalletUtxos(includeSpentMempoolOutputs); for(Collection selectedInputs : selectedInputSets) { total += selectedInputs.stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); Map selectedInputsMap = new LinkedHashMap<>(); @@ -1213,7 +1221,7 @@ public class Wallet extends Persistable implements Comparable { Collections.shuffle(shuffledInputs); } for(BlockTransactionHashIndex shuffledInput : shuffledInputs) { - selectedInputsMap.put(shuffledInput, utxos.get(shuffledInput)); + selectedInputsMap.put(shuffledInput, availableTxos.get(shuffledInput)); } selectedInputSetsList.add(selectedInputsMap); } @@ -1227,18 +1235,18 @@ public class Wallet extends Persistable implements Comparable { throw new InsufficientFundsException("Not enough combined value in UTXOs for output value " + targetValue, targetValue); } - private List getGroupedUtxos(List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { + public List getGroupedUtxos(List txoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress) { List outputGroups = new ArrayList<>(); Map walletTransactions = getWalletTransactions(); Map walletTxos = getWalletTxos(); for(KeyPurpose keyPurpose : getWalletKeyPurposes()) { - getGroupedUtxos(outputGroups, getNode(keyPurpose), utxoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); + getGroupedUtxos(outputGroups, getNode(keyPurpose), txoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress); } for(Wallet childWallet : getChildWallets()) { if(childWallet.isNested()) { for(KeyPurpose keyPurpose : childWallet.getWalletKeyPurposes()) { - childWallet.getGroupedUtxos(outputGroups, childWallet.getNode(keyPurpose), utxoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); + childWallet.getGroupedUtxos(outputGroups, childWallet.getNode(keyPurpose), txoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress); } } } @@ -1246,16 +1254,11 @@ public class Wallet extends Persistable implements Comparable { return outputGroups; } - private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List utxoFilters, Map walletTransactions, Map walletTxos, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { + private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List txoFilters, Map walletTransactions, Map walletTxos, double feeRate, double longTermFeeRate, boolean groupByAddress) { int inputWeightUnits = getInputWeightUnits(); for(WalletNode addressNode : purposeNode.getChildren()) { OutputGroup outputGroup = null; - for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs(includeSpentMempoolOutputs)) { - Optional matchedFilter = utxoFilters.stream().filter(utxoFilter -> !utxoFilter.isEligible(utxo)).findAny(); - if(matchedFilter.isPresent()) { - continue; - } - + for(BlockTransactionHashIndex utxo : addressNode.getTransactionOutputs(txoFilters)) { if(outputGroup == null || !groupByAddress) { outputGroup = new OutputGroup(addressNode.getWallet().getScriptType(), getStoredBlockHeight(), inputWeightUnits, feeRate, longTermFeeRate); outputGroups.add(outputGroup); @@ -1323,12 +1326,12 @@ public class Wallet extends Persistable implements Comparable { * @param feeRate the fee rate in sats/vB * @return the maximum spendable amount (can be negative if the fee is higher than the combined UTXO value) */ - public long getMaxSpendable(List
paymentAddresses, double feeRate, boolean includeSpentMempoolOutputs) { + public long getMaxSpendable(List
paymentAddresses, double feeRate, Map availableTxos) { long maxInputValue = 0; Map cachedInputWeightUnits = new HashMap<>(); Transaction transaction = new Transaction(); - for(Map.Entry utxo : getWalletUtxos(includeSpentMempoolOutputs).entrySet()) { + for(Map.Entry utxo : availableTxos.entrySet()) { int inputWeightUnits = cachedInputWeightUnits.computeIfAbsent(utxo.getValue().getWallet(), Wallet::getInputWeightUnits); long minInputValue = (long)Math.ceil(feeRate * inputWeightUnits / WITNESS_SCALE_FACTOR); if(utxo.getKey().getValue() > minInputValue) { diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java index 4882606..9f05f47 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java @@ -168,16 +168,16 @@ public class WalletNode extends Persistable implements Comparable { } public Set getUnspentTransactionOutputs() { - return getUnspentTransactionOutputs(false); + return getTransactionOutputs(List.of(new SpentTxoFilter())); } - public Set getUnspentTransactionOutputs(boolean includeSpentMempoolOutputs) { + public Set getTransactionOutputs(Collection txoFilters) { if(transactionOutputs.isEmpty()) { return Collections.emptySet(); } Set unspentTXOs = new TreeSet<>(transactionOutputs); - unspentTXOs.removeIf(txo -> txo.isSpent() && (!includeSpentMempoolOutputs || txo.getSpentBy().getHeight() > 0)); + unspentTXOs.removeIf(txo -> !txoFilters.stream().allMatch(txoFilter -> txoFilter.isEligible(txo))); return unspentTXOs; } From 38b04b8e0b802f6cd43b4e88730d4d3ed31227fc Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 11 Jul 2023 11:24:07 +0200 Subject: [PATCH 28/31] fix input vbytes type from int to double --- .../sparrowwallet/drongo/protocol/ScriptType.java | 12 ++++++------ .../drongo/wallet/PresetUtxoSelector.java | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java index f79cd7b..1d45f46 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptType.java @@ -1320,7 +1320,7 @@ public enum ScriptType { //Start with length of output int outputVbytes = output.getLength(); //Add length of spending input (with or without discount depending on script type) - int inputVbytes = getInputVbytes(); + double inputVbytes = getInputVbytes(); //Return fee rate in sats/vByte multiplied by the calculated output and input vByte lengths return (long)(feeRate * outputVbytes + longTermFeeRate * inputVbytes); @@ -1333,17 +1333,17 @@ public enum ScriptType { * * @return The number of vBytes required for an input of this script type */ - public int getInputVbytes() { + public double getInputVbytes() { if(P2SH_P2WPKH.equals(this)) { - return (32 + 4 + 1 + 13 + (107 / WITNESS_SCALE_FACTOR) + 4); + return (32 + 4 + 1 + 13 + ((double)107 / WITNESS_SCALE_FACTOR) + 4); } else if(P2SH_P2WSH.equals(this)) { - return (32 + 4 + 1 + 35 + (107 / WITNESS_SCALE_FACTOR) + 4); + return (32 + 4 + 1 + 35 + ((double)107 / WITNESS_SCALE_FACTOR) + 4); } else if(P2TR.equals(this)) { //Assume a default keypath spend - return (32 + 4 + 1 + (66 / WITNESS_SCALE_FACTOR) + 4); + return (32 + 4 + 1 + ((double)66 / WITNESS_SCALE_FACTOR) + 4); } else if(Arrays.asList(WITNESS_TYPES).contains(this)) { //Return length of spending input with 75% discount to script size - return (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4); + return (32 + 4 + 1 + ((double)107 / WITNESS_SCALE_FACTOR) + 4); } else if(Arrays.asList(NON_WITNESS_TYPES).contains(this)) { //Return length of spending input with no discount return (32 + 4 + 1 + 107 + 4); diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java index 85f4608..64728b4 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/PresetUtxoSelector.java @@ -59,6 +59,13 @@ public class PresetUtxoSelector extends SingleSetUtxoSelector { return excludedUtxos; } + public TxoFilter asExcludeTxoFilter() { + List utxos = new ArrayList<>(); + utxos.addAll(presetUtxos); + utxos.addAll(excludedUtxos); + return new ExcludeTxoFilter(utxos); + } + @Override public boolean shuffleInputs() { return !maintainOrder; From e15eb7c7f36756c35577d61bfd793b2a2502cf93 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Tue, 18 Jul 2023 12:25:24 +0200 Subject: [PATCH 29/31] improve handling of invalid bip322 signatures --- .../sparrowwallet/drongo/crypto/Bip322.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java index 5d38427..700e158 100644 --- a/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java +++ b/src/main/java/com/sparrowwallet/drongo/crypto/Bip322.java @@ -44,6 +44,10 @@ public class Bip322 { public static boolean verifyMessageBip322(ScriptType scriptType, Address address, String message, String signatureBase64) throws SignatureException { checkScriptType(scriptType); + if(signatureBase64.trim().isEmpty()) { + throw new SignatureException("Provided signature is empty."); + } + byte[] signatureEncoded; try { signatureEncoded = Base64.getDecoder().decode(signatureBase64); @@ -51,7 +55,13 @@ public class Bip322 { throw new SignatureException("Could not decode base64 signature", e); } - TransactionWitness witness = new TransactionWitness(null, signatureEncoded, 0); + TransactionWitness witness; + try { + witness = new TransactionWitness(null, signatureEncoded, 0); + } catch(Exception e) { + throw new SignatureException("Provided signature is not a BIP322 simple signature.", e); + } + TransactionSignature signature; ECKey pubKey; @@ -59,8 +69,15 @@ public class Bip322 { throw new IllegalArgumentException("Multisig signatures are not supported."); } + if(witness.getSignatures().isEmpty()) { + throw new SignatureException("BIP322 simple signature contains no transaction signatures."); + } + if(scriptType == ScriptType.P2WPKH) { signature = witness.getSignatures().get(0); + if(witness.getPushes().size() <= 1) { + throw new SignatureException("BIP322 simple signature for P2WPKH script type does not contain a pubkey."); + } pubKey = ECKey.fromPublicOnly(witness.getPushes().get(1)); if(!address.equals(scriptType.getAddress(pubKey))) { From d7b97c99dcd1aa593e7c4354652cd8068aaaeccb Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sun, 23 Jul 2023 12:45:43 +0200 Subject: [PATCH 30/31] add support for parsing compactseedqr without header or ec bytes --- .../sparrowwallet/drongo/wallet/SeedQR.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java b/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java index 9bf9036..e26c06e 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/SeedQR.java @@ -31,25 +31,33 @@ public class SeedQR { } public static DeterministicSeed getSeed(byte[] compactSeedQr) { - if(compactSeedQr[0] != 0x41 && compactSeedQr[0] != 0x42) { - throw new IllegalArgumentException("Invalid CompactSeedQR header"); - } + byte[] seed; - if(compactSeedQr.length < 19) { - throw new IllegalArgumentException("Invalid CompactSeedQR length"); - } - - String qrHex = Utils.bytesToHex(compactSeedQr); - String seedHex; - if(qrHex.endsWith("0ec11ec11")) { - seedHex = qrHex.substring(3, qrHex.length() - 9); //12 word, high EC - } else if(qrHex.endsWith("0ec")) { - seedHex = qrHex.substring(3, qrHex.length() - 3); //12 word, low EC + if(compactSeedQr.length == 16 || compactSeedQr.length == 32) { + //Assume scan contains seed only + seed = compactSeedQr; } else { - seedHex = qrHex.substring(3, qrHex.length() - 1); //24 word - } + //Assume scan contains header, seed and EC bytes + if(compactSeedQr[0] != 0x41 && compactSeedQr[0] != 0x42) { + throw new IllegalArgumentException("Invalid CompactSeedQR header"); + } - byte[] seed = Utils.hexToBytes(seedHex); + if(compactSeedQr.length < 19) { + throw new IllegalArgumentException("Invalid CompactSeedQR length"); + } + + String qrHex = Utils.bytesToHex(compactSeedQr); + String seedHex; + if(qrHex.endsWith("0ec11ec11")) { + seedHex = qrHex.substring(3, qrHex.length() - 9); //12 word, high EC + } else if(qrHex.endsWith("0ec")) { + seedHex = qrHex.substring(3, qrHex.length() - 3); //12 word, low EC + } else { + seedHex = qrHex.substring(3, qrHex.length() - 1); //24 word + } + + seed = Utils.hexToBytes(seedHex); + } if(seed.length < 16 || seed.length > 32 || seed.length % 4 > 0) { throw new IllegalArgumentException("Invalid CompactSeedQR length: " + compactSeedQr.length); From 8313d16e97e708e7674646d43d66cf08b052b863 Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Sun, 23 Jul 2023 13:12:51 +0200 Subject: [PATCH 31/31] fix single character multisig threshold parsing issue --- src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java b/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java index 98294b5..d92883c 100644 --- a/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java +++ b/src/main/java/com/sparrowwallet/drongo/policy/Miniscript.java @@ -6,7 +6,7 @@ import java.util.regex.Pattern; public class Miniscript { private static final Pattern SINGLE_PATTERN = Pattern.compile("pkh?\\("); private static final Pattern TAPROOT_PATTERN = Pattern.compile("tr\\("); - private static final Pattern MULTI_PATTERN = Pattern.compile("multi\\(([\\d+])"); + private static final Pattern MULTI_PATTERN = Pattern.compile("multi\\((\\d+)"); private String script;