rename taproot sighash default and avoid conflation with sighash all

This commit is contained in:
Craig Raw 2022-05-30 16:27:55 +02:00
parent 7535c876ba
commit 7f2c5a5a59
5 changed files with 19 additions and 10 deletions

View file

@ -1,22 +1,27 @@
package com.sparrowwallet.drongo.protocol; package com.sparrowwallet.drongo.protocol;
import java.util.List;
/** /**
* These constants are a part of a scriptSig signature on the inputs. They define the details of how a * These constants are a part of a scriptSig signature on the inputs. They define the details of how a
* transaction can be redeemed, specifically, they control how the hash of the transaction is calculated. * transaction can be redeemed, specifically, they control how the hash of the transaction is calculated.
*/ */
public enum SigHash { public enum SigHash {
ALL("All (Recommended)", (byte)1), ALL("All", (byte)1),
NONE("None", (byte)2), NONE("None", (byte)2),
SINGLE("Single", (byte)3), SINGLE("Single", (byte)3),
ANYONECANPAY("Anyone Can Pay", (byte)0x80), // Caution: Using this type in isolation is non-standard. Treated similar to ANYONECANPAY_ALL. ANYONECANPAY("Anyone Can Pay", (byte)0x80), // Caution: Using this type in isolation is non-standard. Treated similar to ANYONECANPAY_ALL.
ANYONECANPAY_ALL("All + Anyone Can Pay", (byte)0x81), ANYONECANPAY_ALL("All + Anyone Can Pay", (byte)0x81),
ANYONECANPAY_NONE("None + Anyone Can Pay", (byte)0x82), ANYONECANPAY_NONE("None + Anyone Can Pay", (byte)0x82),
ANYONECANPAY_SINGLE("Single + Anyone Can Pay", (byte)0x83), ANYONECANPAY_SINGLE("Single + Anyone Can Pay", (byte)0x83),
ALL_TAPROOT("All (Taproot)", (byte)0); DEFAULT("Default", (byte)0);
private final String name; private final String name;
public final byte value; public final byte value;
public static final List<SigHash> LEGACY_SIGNING_TYPES = List.of(ALL, NONE, SINGLE, ANYONECANPAY_ALL, ANYONECANPAY_NONE, ANYONECANPAY_SINGLE);
public static final List<SigHash> TAPROOT_SIGNING_TYPES = List.of(DEFAULT, ALL, NONE, SINGLE, ANYONECANPAY_ALL, ANYONECANPAY_NONE, ANYONECANPAY_SINGLE);
private SigHash(final String name, final byte value) { private SigHash(final String name, final byte value) {
this.name = name; this.name = name;
this.value = value; this.value = value;

View file

@ -24,7 +24,7 @@ public class TransactionSignature {
/** Constructs a signature with the given components of the given type and SIGHASH_ALL. */ /** Constructs a signature with the given components of the given type and SIGHASH_ALL. */
public TransactionSignature(BigInteger r, BigInteger s, Type type) { public TransactionSignature(BigInteger r, BigInteger s, Type type) {
this(r, s, type, type == Type.ECDSA ? SigHash.ALL.value : SigHash.ALL_TAPROOT.value); this(r, s, type, type == Type.ECDSA ? SigHash.ALL.value : SigHash.DEFAULT.value);
} }
/** Constructs a transaction signature based on the ECDSA signature. */ /** Constructs a transaction signature based on the ECDSA signature. */
@ -60,6 +60,10 @@ public class TransactionSignature {
} }
private SigHash getSigHash() { private SigHash getSigHash() {
if(sighashFlags == SigHash.DEFAULT.byteValue()) {
return SigHash.DEFAULT;
}
boolean anyoneCanPay = anyoneCanPay(); boolean anyoneCanPay = anyoneCanPay();
final int mode = sighashFlags & 0x1f; final int mode = sighashFlags & 0x1f;
if (mode == SigHash.NONE.value) { if (mode == SigHash.NONE.value) {
@ -86,10 +90,10 @@ public class TransactionSignature {
throw new RuntimeException(e); // Cannot happen. throw new RuntimeException(e); // Cannot happen.
} }
} else if(schnorrSignature != null) { } else if(schnorrSignature != null) {
SigHash sigHash = getSigHash(); //Note this will return Sighash.ALL for Sighash.ALL_TAPROOT as well SigHash sigHash = getSigHash();
ByteBuffer buffer = ByteBuffer.allocate(sigHash == SigHash.ALL ? 64 : 65); ByteBuffer buffer = ByteBuffer.allocate(sigHash == SigHash.DEFAULT ? 64 : 65);
buffer.put(schnorrSignature.encode()); buffer.put(schnorrSignature.encode());
if(sigHash != SigHash.ALL) { if(sigHash != SigHash.DEFAULT) {
buffer.put(sighashFlags); buffer.put(sighashFlags);
} }
return buffer.array(); return buffer.array();

View file

@ -513,7 +513,7 @@ public class PSBTInput {
private SigHash getDefaultSigHash() { private SigHash getDefaultSigHash() {
if(isTaproot()) { if(isTaproot()) {
return SigHash.ALL_TAPROOT; return SigHash.DEFAULT;
} }
return SigHash.ALL; return SigHash.ALL;

View file

@ -1365,7 +1365,7 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
Sha256Hash hash; Sha256Hash hash;
if(signingWallet.getScriptType() == P2TR) { if(signingWallet.getScriptType() == P2TR) {
List<TransactionOutput> spentOutputs = transaction.getInputs().stream().map(input -> signingWallet.transactions.get(input.getOutpoint().getHash()).getTransaction().getOutputs().get((int)input.getOutpoint().getIndex())).collect(Collectors.toList()); List<TransactionOutput> spentOutputs = transaction.getInputs().stream().map(input -> signingWallet.transactions.get(input.getOutpoint().getHash()).getTransaction().getOutputs().get((int)input.getOutpoint().getIndex())).collect(Collectors.toList());
hash = transaction.hashForTaprootSignature(spentOutputs, txInput.getIndex(), !P2TR.isScriptType(signingScript), signingScript, SigHash.ALL_TAPROOT, null); hash = transaction.hashForTaprootSignature(spentOutputs, txInput.getIndex(), !P2TR.isScriptType(signingScript), signingScript, SigHash.DEFAULT, null);
} else if(txInput.hasWitness()) { } else if(txInput.hasWitness()) {
hash = transaction.hashForWitnessSignature(txInput.getIndex(), signingScript, spentTxo.getValue(), SigHash.ALL); hash = transaction.hashForWitnessSignature(txInput.getIndex(), signingScript, spentTxo.getValue(), SigHash.ALL);
} else { } else {

View file

@ -494,13 +494,13 @@ public class TransactionTest {
Transaction tx = new Transaction(Utils.hexToBytes("02000000000101786ed355f998b98f8ef8ef2acf461577325cf170a9133d48a17aba957eb97ff00000000000ffffffff0100e1f50500000000220020693a94699e6e41ab302fd623a9bf5a5b2d6606cbfb35c550d1cb4300451356a102473044022004cc317c20eb9e372cb0e640f51eb2b8311616125321b11dbaa5671db5a3ca2a02207ae3d2771b565be98ae56e21045b9629c94b6ca8f4e3932260e54d4f0e2016b30121032da1692a41a61ad14f3795b31d33431abf8d6ee161b997d004c26a37bc20083500000000")); Transaction tx = new Transaction(Utils.hexToBytes("02000000000101786ed355f998b98f8ef8ef2acf461577325cf170a9133d48a17aba957eb97ff00000000000ffffffff0100e1f50500000000220020693a94699e6e41ab302fd623a9bf5a5b2d6606cbfb35c550d1cb4300451356a102473044022004cc317c20eb9e372cb0e640f51eb2b8311616125321b11dbaa5671db5a3ca2a02207ae3d2771b565be98ae56e21045b9629c94b6ca8f4e3932260e54d4f0e2016b30121032da1692a41a61ad14f3795b31d33431abf8d6ee161b997d004c26a37bc20083500000000"));
Transaction spendingTx = new Transaction(Utils.hexToBytes("01000000011af4dca4a6bc6da092edca5390355891da9bbe76d2be1c04d067ec9c3a3d22b10000000000000000000180f0fa0200000000160014a3bcb5f272025cc66dc42e7518a5846bd60a9c9600000000")); Transaction spendingTx = new Transaction(Utils.hexToBytes("01000000011af4dca4a6bc6da092edca5390355891da9bbe76d2be1c04d067ec9c3a3d22b10000000000000000000180f0fa0200000000160014a3bcb5f272025cc66dc42e7518a5846bd60a9c9600000000"));
Sha256Hash hash = spendingTx.hashForTaprootSignature(tx.getOutputs(), 0, false, null, SigHash.ALL_TAPROOT, null); Sha256Hash hash = spendingTx.hashForTaprootSignature(tx.getOutputs(), 0, false, null, SigHash.DEFAULT, null);
ECKey privateKey = ECKey.fromPrivate(Utils.hexToBytes("d9bc817b92916a24b87d25dc48ef466b4fcd6c89cf90afbc17cba40eb8b91330")); ECKey privateKey = ECKey.fromPrivate(Utils.hexToBytes("d9bc817b92916a24b87d25dc48ef466b4fcd6c89cf90afbc17cba40eb8b91330"));
SchnorrSignature sig = privateKey.signSchnorr(hash); SchnorrSignature sig = privateKey.signSchnorr(hash);
Assert.assertEquals("7b04f59bc8f5c2c33c9b8acbf94743de74cc25a6052b52ff61a516f7c5ca19cc68345ba99b354f22bfaf5c04de395b9223f3bf0a5c351fc1cc68c224f4e5b202", Utils.bytesToHex(sig.encode())); Assert.assertEquals("7b04f59bc8f5c2c33c9b8acbf94743de74cc25a6052b52ff61a516f7c5ca19cc68345ba99b354f22bfaf5c04de395b9223f3bf0a5c351fc1cc68c224f4e5b202", Utils.bytesToHex(sig.encode()));
ECKey pubKey = ECKey.fromPublicOnly(privateKey); ECKey pubKey = ECKey.fromPublicOnly(privateKey);
Assert.assertTrue(pubKey.verify(hash, new TransactionSignature(sig, SigHash.ALL_TAPROOT))); Assert.assertTrue(pubKey.verify(hash, new TransactionSignature(sig, SigHash.DEFAULT)));
} }
} }