diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java index bf05d97..1592df8 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptChunk.java @@ -11,6 +11,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; +import java.util.stream.IntStream; import static com.sparrowwallet.drongo.protocol.ScriptOpCodes.*; @@ -150,7 +151,7 @@ public class ScriptChunk { return false; } - if(isSignature() || isPubKey()) { + if(isSignature() || isPubKey() || isTaprootControlBlock()) { return false; } @@ -180,13 +181,22 @@ public class ScriptChunk { return false; } - return ECKey.isPubKeyCanonical(data); + return ECKey.isPubKeyCanonical(data) && !IntStream.range(0, data.length).mapToObj(i -> data[i]).allMatch(b -> b == 0); } public ECKey getPubKey() { return ECKey.fromPublicOnly(data); } + public boolean isTaprootControlBlock() { + if(data == null || data.length == 0 || (data.length - 1) % 32 != 0) { + return false; + } + + //Test for BIP341 leaf version and both parity options + return ((data[0] & 0xff) == 0xc0 || (data[0] & 0xff) == 0xc1); + } + public byte[] toByteArray() { ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { diff --git a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptOpCodes.java b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptOpCodes.java index 0b7e9c0..7623706 100644 --- a/src/main/java/com/sparrowwallet/drongo/protocol/ScriptOpCodes.java +++ b/src/main/java/com/sparrowwallet/drongo/protocol/ScriptOpCodes.java @@ -161,6 +161,7 @@ public class ScriptOpCodes { public static final int OP_NOP8 = 0xb7; public static final int OP_NOP9 = 0xb8; public static final int OP_NOP10 = 0xb9; + public static final int OP_CHECKSIGADD = 0xba; public static final int OP_INVALIDOPCODE = 0xff; private static final Map opCodeNameMap; @@ -269,6 +270,7 @@ public class ScriptOpCodes { opCodeNameMap.put(OP_CHECKSIGVERIFY, "CHECKSIGVERIFY"); opCodeNameMap.put(OP_CHECKMULTISIG, "CHECKMULTISIG"); opCodeNameMap.put(OP_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"); + opCodeNameMap.put(OP_CHECKSIGADD, "CHECKSIGADD"); opCodeNameMap.put(OP_NOP1, "NOP1"); opCodeNameMap.put(OP_CHECKLOCKTIMEVERIFY, "CHECKLOCKTIMEVERIFY"); opCodeNameMap.put(OP_CHECKSEQUENCEVERIFY, "CHECKSEQUENCEVERIFY");