getTransactionTaprootDigset method

Uint8List getTransactionTaprootDigset({
  1. required int txIndex,
  2. required List<Script> scriptPubKeys,
  3. required List<BigInt> amounts,
  4. int extFlags = 0,
  5. Script script = const Script(script: []),
  6. int leafVar = LEAF_VERSION_TAPSCRIPT,
  7. int sighash = TAPROOT_SIGHASH_ALL,
})

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");
}