getTransactionTaprootDigset method
Returns the segwit v1 (taproot) transaction's digest for signing.
txIndex
The index of the input that we wish to sign
scriptPubKeys
he scriptPubkeys that correspond to all the inputs/UTXOs
amounts
The amounts that correspond to all the inputs/UTXOs
extFlags
Extension mechanism, default is 0; 1 is for script spending (BIP342)
script
The script that we are spending (ext_flag=1)
leafVar
The script version, LEAF_VERSION_TAPSCRIPT for the default tapscript
sighash
The type of the signature hash to be created
Implementation
Uint8List getTransactionTaprootDigset(
{required int txIndex,
required List<Script> scriptPubKeys,
required List<BigInt> amounts,
int extFlags = 0,
Script script = const Script(script: []),
int leafVar = LEAF_VERSION_TAPSCRIPT,
int sighash = TAPROOT_SIGHASH_ALL}) {
final newTx = copy(this);
bool sighashNone = (sighash & 0x03) == SIGHASH_NONE;
bool sighashSingle = (sighash & 0x03) == SIGHASH_SINGLE;
bool anyoneCanPay = (sighash & 0x80) == SIGHASH_ANYONECANPAY;
DynamicByteTracker txForSign = DynamicByteTracker();
txForSign.add([0]);
txForSign.add(Uint16List.fromList([sighash]));
txForSign.add(version);
txForSign.add(locktime);
Uint8List hashPrevouts = Uint8List(0);
Uint8List hashAmounts = Uint8List(0);
Uint8List hashScriptPubkeys = Uint8List(0);
Uint8List hashSequences = Uint8List(0);
Uint8List hashOutputs = Uint8List(0);
if (!anyoneCanPay) {
for (final txin in newTx.inputs) {
Uint8List txidBytes =
Uint8List.fromList(hexToBytes(txin.txId).reversed.toList());
Uint8List txoutIndexBytes = packUint32LE(txin.txIndex);
hashPrevouts = Uint8List.fromList(
[...hashPrevouts, ...txidBytes, ...txoutIndexBytes]);
}
hashPrevouts = singleHash(hashPrevouts);
txForSign.add(hashPrevouts);
for (final i in amounts) {
Uint8List bytes = packBigIntToLittleEndian(i);
hashAmounts = Uint8List.fromList([...hashAmounts, ...bytes]);
}
hashAmounts = singleHash(hashAmounts);
txForSign.add(hashAmounts);
for (final s in scriptPubKeys) {
final h = s.toHex(); // must checked
int scriptLen = h.length ~/ 2;
Uint8List scriptBytes = hexToBytes(h);
Uint8List lenBytes = Uint8List.fromList([scriptLen]);
hashScriptPubkeys = Uint8List.fromList(
[...hashScriptPubkeys, ...lenBytes, ...scriptBytes]);
}
hashScriptPubkeys = singleHash(hashScriptPubkeys);
txForSign.add(hashScriptPubkeys);
for (final txIn in newTx.inputs) {
hashSequences =
Uint8List.fromList([...hashSequences, ...txIn.sequence]);
}
hashSequences = singleHash(hashSequences);
txForSign.add(hashSequences);
}
if (!(sighashNone || sighashSingle)) {
for (final txOut in newTx.outputs) {
Uint8List packedAmount = packBigIntToLittleEndian(txOut.amount);
Uint8List scriptBytes = txOut.scriptPubKey.toBytes();
final lenScriptBytes = Uint8List.fromList([scriptBytes.length]);
hashOutputs = Uint8List.fromList([
...hashOutputs,
...packedAmount,
...lenScriptBytes,
...scriptBytes
]);
}
hashOutputs = singleHash(hashOutputs);
txForSign.add(hashOutputs);
}
final int spendType = extFlags * 2 + 0;
txForSign.add(Uint8List.fromList([spendType]));
if (anyoneCanPay) {
final txin = newTx.inputs[txIndex];
Uint8List txidBytes =
Uint8List.fromList(hexToBytes(txin.txId).reversed.toList());
Uint8List txoutIndexBytes = packUint32LE(txin.txIndex);
Uint8List result = Uint8List.fromList([...txidBytes, ...txoutIndexBytes]);
txForSign.add(result);
txForSign.add(packBigIntToLittleEndian(amounts[txIndex]));
final sPubKey = scriptPubKeys[txIndex].toHex();
final sLength = sPubKey.length ~/ 2;
txForSign.add(Uint16List.fromList([sLength]));
txForSign.add(hexToBytes(sPubKey));
txForSign.add(txin.sequence);
} else {
int index = txIndex;
ByteData byteData = ByteData(4);
for (int i = 0; i < 4; i++) {
byteData.setUint8(i, index & 0xFF);
index >>= 8;
}
Uint8List bytes = byteData.buffer.asUint8List();
txForSign.add(bytes);
}
if (sighashSingle) {
final txOut = newTx.outputs[txIndex];
Uint8List packedAmount = packBigIntToLittleEndian(txOut.amount);
final sBytes = txOut.scriptPubKey.toBytes();
Uint8List lenScriptBytes = Uint8List.fromList([sBytes.length]);
final hashOut =
Uint8List.fromList([...packedAmount, ...lenScriptBytes, ...sBytes]);
txForSign.add(singleHash(hashOut));
}
if (extFlags == 1) {
leafVar = LEAF_VERSION_TAPSCRIPT;
final leafVarBytes = Uint8List.fromList([
...Uint8List.fromList([leafVar]),
...prependVarint(script.toBytes())
]);
txForSign.add(taggedHash(leafVarBytes, "TapLeaf"));
txForSign.add(Uint16List.fromList([0]));
txForSign.add(Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF]));
}
final bytes = txForSign.toBytes();
txForSign.close();
return taggedHash(bytes, "TapSighash");
}