move sighash to top level, psbt signing status tests

This commit is contained in:
Craig Raw 2020-07-17 17:24:15 +02:00
parent a56684240a
commit dcd4218ba1
8 changed files with 174 additions and 86 deletions

View file

@ -0,0 +1,60 @@
package com.sparrowwallet.drongo.protocol;
/**
* 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.
*/
public enum SigHash {
ALL("All (Recommended)", 1),
NONE("None", 2),
SINGLE("Single", 3),
ANYONECANPAY("Anyone Can Pay", 0x80), // Caution: Using this type in isolation is non-standard. Treated similar to ANYONECANPAY_ALL.
ANYONECANPAY_ALL("All + Anyone Can Pay", 0x81),
ANYONECANPAY_NONE("None + Anyone Can Pay", 0x82),
ANYONECANPAY_SINGLE("Single + Anyone Can Pay", 0x83),
UNSET("Unset", 0); // Caution: Using this type in isolation is non-standard. Treated similar to ALL.
private final String name;
public final int value;
/**
* @param value
*/
private SigHash(final String name, final int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
/**
* @return the value as a int
*/
public int intValue() {
return this.value;
}
/**
* @return the value as a byte
*/
public byte byteValue() {
return (byte) this.value;
}
public static SigHash fromInt(int sigHashInt) {
for(SigHash value : SigHash.values()) {
if(sigHashInt == value.intValue()) {
return value;
}
}
throw new IllegalArgumentException("No defined sighash value for int " + sigHashInt);
}
@Override
public String toString() {
return getName();
}
}

View file

@ -561,54 +561,6 @@ public class Transaction extends ChildMessage {
return Sha256Hash.twiceOf(bos.toByteArray()); return Sha256Hash.twiceOf(bos.toByteArray());
} }
/**
* 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.
*/
public enum SigHash {
ALL(1),
NONE(2),
SINGLE(3),
ANYONECANPAY(0x80), // Caution: Using this type in isolation is non-standard. Treated similar to ANYONECANPAY_ALL.
ANYONECANPAY_ALL(0x81),
ANYONECANPAY_NONE(0x82),
ANYONECANPAY_SINGLE(0x83),
UNSET(0); // Caution: Using this type in isolation is non-standard. Treated similar to ALL.
public final int value;
/**
* @param value
*/
private SigHash(final int value) {
this.value = value;
}
/**
* @return the value as a int
*/
public int intValue() {
return this.value;
}
/**
* @return the value as a byte
*/
public byte byteValue() {
return (byte) this.value;
}
public static SigHash fromInt(int sigHashInt) {
for(SigHash value : SigHash.values()) {
if(sigHashInt == value.intValue()) {
return value;
}
}
throw new IllegalArgumentException("No defined sighash value for int " + sigHashInt);
}
}
public static final void main(String[] args) throws NonStandardScriptException { public static final void main(String[] args) throws NonStandardScriptException {
String hex = "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000"; String hex = "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000";
byte[] transactionBytes = Utils.hexToBytes(hex); byte[] transactionBytes = Utils.hexToBytes(hex);

View file

@ -17,7 +17,7 @@ public class TransactionSignature extends ECKey.ECDSASignature {
/** Constructs a signature with the given components and SIGHASH_ALL. */ /** Constructs a signature with the given components and SIGHASH_ALL. */
public TransactionSignature(BigInteger r, BigInteger s) { public TransactionSignature(BigInteger r, BigInteger s) {
this(r, s, Transaction.SigHash.ALL.value); this(r, s, SigHash.ALL.value);
} }
/** Constructs a signature with the given components and raw sighash flag bytes (needed for rule compatibility). */ /** Constructs a signature with the given components and raw sighash flag bytes (needed for rule compatibility). */
@ -27,7 +27,7 @@ public class TransactionSignature extends ECKey.ECDSASignature {
} }
/** Constructs a transaction signature based on the ECDSA signature. */ /** Constructs a transaction signature based on the ECDSA signature. */
public TransactionSignature(ECKey.ECDSASignature signature, Transaction.SigHash mode, boolean anyoneCanPay) { public TransactionSignature(ECKey.ECDSASignature signature, SigHash mode, boolean anyoneCanPay) {
super(signature.r, signature.s); super(signature.r, signature.s);
sighashFlags = calcSigHashValue(mode, anyoneCanPay); sighashFlags = calcSigHashValue(mode, anyoneCanPay);
} }
@ -44,13 +44,13 @@ public class TransactionSignature extends ECKey.ECDSASignature {
} }
/** Calculates the byte used in the protocol to represent the combination of mode and anyoneCanPay. */ /** Calculates the byte used in the protocol to represent the combination of mode and anyoneCanPay. */
public static int calcSigHashValue(Transaction.SigHash mode, boolean anyoneCanPay) { public static int calcSigHashValue(SigHash mode, boolean anyoneCanPay) {
if(Transaction.SigHash.ALL != mode && Transaction.SigHash.NONE != mode && Transaction.SigHash.SINGLE != mode) { // enforce compatibility since this code was made before the SigHash enum was updated if(SigHash.ALL != mode && SigHash.NONE != mode && SigHash.SINGLE != mode) { // enforce compatibility since this code was made before the SigHash enum was updated
throw new IllegalArgumentException("Sighash mode must be one of ALL, NONE or SINGLE"); throw new IllegalArgumentException("Sighash mode must be one of ALL, NONE or SINGLE");
} }
int sighashFlags = mode.value; int sighashFlags = mode.value;
if (anyoneCanPay) if (anyoneCanPay)
sighashFlags |= Transaction.SigHash.ANYONECANPAY.value; sighashFlags |= SigHash.ANYONECANPAY.value;
return sighashFlags; return sighashFlags;
} }
@ -76,8 +76,8 @@ public class TransactionSignature extends ECKey.ECDSASignature {
if (signature.length < 9 || signature.length > 73) if (signature.length < 9 || signature.length > 73)
return false; return false;
int hashType = (signature[signature.length-1] & 0xff) & ~Transaction.SigHash.ANYONECANPAY.value; // mask the byte to prevent sign-extension hurting us int hashType = (signature[signature.length-1] & 0xff) & ~SigHash.ANYONECANPAY.value; // mask the byte to prevent sign-extension hurting us
if (hashType < Transaction.SigHash.ALL.value || hashType > Transaction.SigHash.SINGLE.value) if (hashType < SigHash.ALL.value || hashType > SigHash.SINGLE.value)
return false; return false;
// "wrong type" "wrong length marker" // "wrong type" "wrong length marker"
@ -107,17 +107,17 @@ public class TransactionSignature extends ECKey.ECDSASignature {
} }
public boolean anyoneCanPay() { public boolean anyoneCanPay() {
return (sighashFlags & Transaction.SigHash.ANYONECANPAY.value) != 0; return (sighashFlags & SigHash.ANYONECANPAY.value) != 0;
} }
public Transaction.SigHash sigHashMode() { public SigHash sigHashMode() {
final int mode = sighashFlags & 0x1f; final int mode = sighashFlags & 0x1f;
if (mode == Transaction.SigHash.NONE.value) if (mode == SigHash.NONE.value)
return Transaction.SigHash.NONE; return SigHash.NONE;
else if (mode == Transaction.SigHash.SINGLE.value) else if (mode == SigHash.SINGLE.value)
return Transaction.SigHash.SINGLE; return SigHash.SINGLE;
else else
return Transaction.SigHash.ALL; return SigHash.ALL;
} }
/** /**

View file

@ -388,6 +388,26 @@ public class PSBT {
return fee; return fee;
} }
public boolean hasSignatures() {
for(PSBTInput psbtInput : getPsbtInputs()) {
if(!psbtInput.getPartialSignatures().isEmpty() || psbtInput.getFinalScriptSig() != null || psbtInput.getFinalScriptWitness() != null) {
return true;
}
}
return false;
}
public boolean isSigned() {
for(PSBTInput psbtInput : getPsbtInputs()) {
if(!psbtInput.isSigned()) {
return false;
}
}
return true;
}
public byte[] serialize() throws IOException { public byte[] serialize() throws IOException {
ByteArrayOutputStream transactionbaos = new ByteArrayOutputStream(); ByteArrayOutputStream transactionbaos = new ByteArrayOutputStream();
transaction.bitcoinSerializeToStream(transactionbaos); transaction.bitcoinSerializeToStream(transactionbaos);

View file

@ -30,7 +30,7 @@ public class PSBTInput {
private Transaction nonWitnessUtxo; private Transaction nonWitnessUtxo;
private TransactionOutput witnessUtxo; private TransactionOutput witnessUtxo;
private final Map<ECKey, TransactionSignature> partialSignatures = new LinkedHashMap<>(); private final Map<ECKey, TransactionSignature> partialSignatures = new LinkedHashMap<>();
private Transaction.SigHash sigHash; private SigHash sigHash;
private Script redeemScript; private Script redeemScript;
private Script witnessScript; private Script witnessScript;
private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>(); private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
@ -47,7 +47,7 @@ public class PSBTInput {
PSBTInput(ScriptType scriptType, Transaction transaction, int index, Transaction utxo, int utxoIndex, Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary) { PSBTInput(ScriptType scriptType, Transaction transaction, int index, Transaction utxo, int utxoIndex, Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary) {
this.transaction = transaction; this.transaction = transaction;
this.index = index; this.index = index;
sigHash = Transaction.SigHash.ALL; sigHash = SigHash.ALL;
if(Arrays.asList(ScriptType.WITNESS_TYPES).contains(scriptType)) { if(Arrays.asList(ScriptType.WITNESS_TYPES).contains(scriptType)) {
this.witnessUtxo = utxo.getOutputs().get(utxoIndex); this.witnessUtxo = utxo.getOutputs().get(utxoIndex);
@ -118,7 +118,7 @@ public class PSBTInput {
case PSBT_IN_SIGHASH_TYPE: case PSBT_IN_SIGHASH_TYPE:
entry.checkOneByteKey(); entry.checkOneByteKey();
long sighashType = Utils.readUint32(entry.getData(), 0); long sighashType = Utils.readUint32(entry.getData(), 0);
Transaction.SigHash sigHash = Transaction.SigHash.fromInt((int)sighashType); SigHash sigHash = SigHash.fromInt((int)sighashType);
this.sigHash = sigHash; this.sigHash = sigHash;
log.debug("Found input sighash_type " + sigHash.toString()); log.debug("Found input sighash_type " + sigHash.toString());
break; break;
@ -211,10 +211,14 @@ public class PSBTInput {
return partialSignatures.get(publicKey); return partialSignatures.get(publicKey);
} }
public Transaction.SigHash getSigHash() { public SigHash getSigHash() {
return sigHash; return sigHash;
} }
public void setSigHash(SigHash sigHash) {
this.sigHash = sigHash;
}
public Script getRedeemScript() { public Script getRedeemScript() {
return redeemScript; return redeemScript;
} }
@ -261,18 +265,26 @@ public class PSBTInput {
return proprietary; return proprietary;
} }
public boolean isSigned() throws NonStandardScriptException { public boolean isSigned() {
//All partial sigs are already verified if(!getPartialSignatures().isEmpty()) {
int reqSigs = getSigningScript().getNumRequiredSignatures(); try {
int sigs = getPartialSignatures().size(); //All partial sigs are already verified
return sigs == reqSigs; int reqSigs = getSigningScript().getNumRequiredSignatures();
int sigs = getPartialSignatures().size();
return sigs == reqSigs;
} catch(NonStandardScriptException e) {
return false;
}
} else {
return getFinalScriptSig() != null;
}
} }
boolean verifySignatures() throws PSBTParseException { boolean verifySignatures() throws PSBTParseException {
Transaction.SigHash localSigHash = getSigHash(); SigHash localSigHash = getSigHash();
if(localSigHash == null) { if(localSigHash == null) {
//Assume SigHash.ALL //Assume SigHash.ALL
localSigHash = Transaction.SigHash.ALL; localSigHash = SigHash.ALL;
} }
if(getNonWitnessUtxo() != null || getWitnessUtxo() != null) { if(getNonWitnessUtxo() != null || getWitnessUtxo() != null) {
@ -325,7 +337,7 @@ public class PSBTInput {
return signingScript; return signingScript;
} }
private Sha256Hash getHashForSignature(Script connectedScript, Transaction.SigHash localSigHash) { private Sha256Hash getHashForSignature(Script connectedScript, SigHash localSigHash) {
Sha256Hash hash; Sha256Hash hash;
if (getNonWitnessUtxo() != null) { if (getNonWitnessUtxo() != null) {
hash = transaction.hashForSignature(index, connectedScript, localSigHash, false); hash = transaction.hashForSignature(index, connectedScript, localSigHash, false);

View file

@ -8,6 +8,8 @@ import com.sparrowwallet.drongo.crypto.Key;
import com.sparrowwallet.drongo.policy.Policy; import com.sparrowwallet.drongo.policy.Policy;
import com.sparrowwallet.drongo.policy.PolicyType; import com.sparrowwallet.drongo.policy.PolicyType;
import com.sparrowwallet.drongo.protocol.*; import com.sparrowwallet.drongo.protocol.*;
import com.sparrowwallet.drongo.psbt.PSBT;
import com.sparrowwallet.drongo.psbt.PSBTInput;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -251,6 +253,23 @@ public class Wallet {
} }
} }
public boolean isWalletOutputScript(Script outputScript) {
return getWalletOutputScripts().containsKey(outputScript);
}
public Map<Script, WalletNode> getWalletOutputScripts() {
Map<Script, WalletNode> walletOutputScripts = new LinkedHashMap<>();
getWalletOutputScripts(walletOutputScripts, getNode(KeyPurpose.RECEIVE));
getWalletOutputScripts(walletOutputScripts, getNode(KeyPurpose.CHANGE));
return walletOutputScripts;
}
private void getWalletOutputScripts(Map<Script, WalletNode> walletOutputScripts, WalletNode purposeNode) {
for(WalletNode addressNode : purposeNode.getChildren()) {
walletOutputScripts.put(getOutputScript(addressNode), addressNode);
}
}
public boolean isWalletTxo(BlockTransactionHashIndex txo) { public boolean isWalletTxo(BlockTransactionHashIndex txo) {
return getWalletTxos().containsKey(txo); return getWalletTxos().containsKey(txo);
} }
@ -549,6 +568,27 @@ public class Wallet {
return true; return true;
} }
public boolean canSign(PSBT psbt) {
for(int inputIndex = 0; inputIndex < psbt.getTransaction().getInputs().size(); inputIndex++) {
TransactionInput txInput = psbt.getTransaction().getInputs().get(inputIndex);
PSBTInput psbtInput = psbt.getPsbtInputs().get(inputIndex);
TransactionOutput utxo = psbtInput.getWitnessUtxo();
if(utxo == null) {
utxo = psbtInput.getNonWitnessUtxo().getOutputs().get((int)txInput.getOutpoint().getIndex());
}
if(utxo != null) {
Script scriptPubKey = utxo.getScript();
if(isWalletOutputScript(scriptPubKey)) {
return true;
}
}
}
return false;
}
public BitcoinUnit getAutoUnit() { public BitcoinUnit getAutoUnit() {
for(KeyPurpose keyPurpose : KeyPurpose.values()) { for(KeyPurpose keyPurpose : KeyPurpose.values()) {
for(WalletNode addressNode : getNode(keyPurpose).getChildren()) { for(WalletNode addressNode : getNode(keyPurpose).getChildren()) {
@ -737,4 +777,8 @@ public class Wallet {
} }
} }
@Override
public String toString() {
return getName();
}
} }

View file

@ -18,7 +18,7 @@ public class TransactionTest {
Transaction transaction = new Transaction(Utils.hexToBytes(hex)); Transaction transaction = new Transaction(Utils.hexToBytes(hex));
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"));
Sha256Hash hash = transaction.hashForWitnessSignature(1, ScriptType.P2PKH.getOutputScript(pubKey.getPubKeyHash()),600000000L, Transaction.SigHash.ALL, false); Sha256Hash hash = transaction.hashForWitnessSignature(1, ScriptType.P2PKH.getOutputScript(pubKey.getPubKeyHash()),600000000L, SigHash.ALL, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee"), false, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee"), false, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -29,7 +29,7 @@ public class TransactionTest {
Transaction transaction = new Transaction(Utils.hexToBytes(hex)); Transaction transaction = new Transaction(Utils.hexToBytes(hex));
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, ScriptType.P2PKH.getOutputScript(pubKey.getPubKeyHash()),1000000000L, Transaction.SigHash.ALL, false); Sha256Hash hash = transaction.hashForWitnessSignature(0, ScriptType.P2PKH.getOutputScript(pubKey.getPubKeyHash()),1000000000L, SigHash.ALL, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb01"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb01"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -41,7 +41,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880ae")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880ae"));
Script script = new Script(Utils.hexToBytes("21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac")); Script script = new Script(Utils.hexToBytes("21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac"));
Sha256Hash hash = transaction.hashForWitnessSignature(1, script,4900000000L, Transaction.SigHash.SINGLE, false); Sha256Hash hash = transaction.hashForWitnessSignature(1, script,4900000000L, SigHash.SINGLE, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e2703"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e2703"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -53,7 +53,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98"));
Script script = new Script(Utils.hexToBytes("68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac")); Script script = new Script(Utils.hexToBytes("68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac"));
Sha256Hash hash = transaction.hashForWitnessSignature(1, script,16777215L, Transaction.SigHash.SINGLE, true); Sha256Hash hash = transaction.hashForWitnessSignature(1, script,16777215L, SigHash.SINGLE, true);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("30440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("30440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -65,7 +65,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.ALL, false); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.ALL, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -77,7 +77,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.NONE, false); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.NONE, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -89,7 +89,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.SINGLE, false); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.SINGLE, false);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -101,7 +101,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.ALL, true); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.ALL, true);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -113,7 +113,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.NONE, true); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.NONE, true);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a0882"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("3045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a0882"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }
@ -125,7 +125,7 @@ public class TransactionTest {
ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b")); ECKey pubKey = ECKey.fromPublicOnly(Utils.hexToBytes("02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b"));
Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae")); Script script = new Script(Utils.hexToBytes("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"));
Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, Transaction.SigHash.SINGLE, true); Sha256Hash hash = transaction.hashForWitnessSignature(0, script,987654321L, SigHash.SINGLE, true);
TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("30440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783"), true, true); TransactionSignature signature = TransactionSignature.decodeFromBitcoin(Utils.hexToBytes("30440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783"), true, true);
Assert.assertTrue(pubKey.verify(hash, signature)); Assert.assertTrue(pubKey.verify(hash, signature));
} }

View file

@ -3,7 +3,7 @@ package com.sparrowwallet.drongo.psbt;
import com.sparrowwallet.drongo.ExtendedKey; import com.sparrowwallet.drongo.ExtendedKey;
import com.sparrowwallet.drongo.KeyDerivation; import com.sparrowwallet.drongo.KeyDerivation;
import com.sparrowwallet.drongo.protocol.NonStandardScriptException; import com.sparrowwallet.drongo.protocol.NonStandardScriptException;
import com.sparrowwallet.drongo.protocol.Transaction; import com.sparrowwallet.drongo.protocol.SigHash;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -170,7 +170,7 @@ public class PSBTTest {
public void validP2pkhWithSigHash() throws PSBTParseException { public void validP2pkhWithSigHash() throws PSBTParseException {
String psbt = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA=="; String psbt = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA==";
PSBT psbt1 = PSBT.fromString(psbt); PSBT psbt1 = PSBT.fromString(psbt);
Assert.assertEquals(Transaction.SigHash.ALL, psbt1.getPsbtInputs().get(0).getSigHash()); Assert.assertEquals(SigHash.ALL, psbt1.getPsbtInputs().get(0).getSigHash());
Assert.assertEquals(301L, psbt1.getFee().longValue()); Assert.assertEquals(301L, psbt1.getFee().longValue());
} }