getTransactionSegwitDigit method
returns the transaction input's segwit digest that is to be signed according to sighash.
txInIndex
The index of the input that we wish to sign.
script
The scriptCode (template) that corresponds to the segwit, transaction output type that we want to spend.
amount
The amount of the UTXO to spend is included in the signature for segwit (in satoshis).
sighash
The type of the signature hash to be created.
Implementation
Uint8List getTransactionSegwitDigit(
{required int txInIndex,
required Script script,
int sighash = SIGHASH_ALL,
required BigInt amount}) {
final tx = copy(this);
Uint8List hashPrevouts = Uint8List(32);
Uint8List hashSequence = Uint8List(32);
Uint8List hashOutputs = Uint8List(32);
int basicSigHashType = sighash & 0x1F;
bool anyoneCanPay = (sighash & 0xF0) == SIGHASH_ANYONECANPAY;
bool signAll = (basicSigHashType != SIGHASH_SINGLE) &&
(basicSigHashType != SIGHASH_NONE);
if (!anyoneCanPay) {
hashPrevouts = Uint8List(0);
for (final txin in tx.inputs) {
Uint8List txidBytes =
Uint8List.fromList(hexToBytes(txin.txId).reversed.toList());
Uint8List txoutIndexBytes = packUint32LE(txin.txIndex);
hashPrevouts = Uint8List.fromList(
[...hashPrevouts, ...txidBytes, ...txoutIndexBytes]);
}
hashPrevouts = doubleHash(hashPrevouts);
}
if (!anyoneCanPay && signAll) {
hashSequence = Uint8List(0);
for (final i in tx.inputs) {
hashSequence = Uint8List.fromList([...hashSequence, ...i.sequence]);
}
hashSequence = doubleHash(hashSequence);
}
if (signAll) {
hashOutputs = Uint8List(0);
for (final i in tx.outputs) {
Uint8List amountBytes = packBigIntToLittleEndian(i.amount);
Uint8List scriptBytes = i.scriptPubKey.toBytes();
hashOutputs = Uint8List.fromList([
...hashOutputs,
...amountBytes,
scriptBytes.length,
...scriptBytes
]);
}
hashOutputs = doubleHash(hashOutputs);
} else if (basicSigHashType == SIGHASH_SINGLE &&
txInIndex < tx.outputs.length) {
final out = tx.outputs[txInIndex];
Uint8List packedAmount = packBigIntToLittleEndian(out.amount);
final scriptBytes = out.scriptPubKey.toBytes();
Uint8List lenScriptBytes = Uint8List.fromList([scriptBytes.length]);
hashOutputs = Uint8List.fromList(
[...packedAmount, ...lenScriptBytes, ...scriptBytes]);
hashOutputs = doubleHash(hashOutputs);
}
DynamicByteTracker txForSigning = DynamicByteTracker();
txForSigning.add(version);
txForSigning.add(hashPrevouts);
txForSigning.add(hashSequence);
final txIn = inputs[txInIndex];
Uint8List txidBytes =
Uint8List.fromList(hexToBytes(txIn.txId).reversed.toList());
Uint8List txoutIndexBytes = packUint32LE(txIn.txIndex);
txForSigning.add(Uint8List.fromList([...txidBytes, ...txoutIndexBytes]));
txForSigning.add(Uint8List.fromList([script.toBytes().length]));
txForSigning.add(script.toBytes());
Uint8List packedAmount = packBigIntToLittleEndian(amount);
txForSigning.add(packedAmount);
txForSigning.add(txIn.sequence);
txForSigning.add(hashOutputs);
txForSigning.add(locktime);
Uint8List packedSighash = packInt32LE(sighash);
txForSigning.add(packedSighash);
txForSigning.close();
return doubleHash(txForSigning.toBytes());
}