hashForWitnessV1 method

Uint8List hashForWitnessV1(
  1. int inIndex,
  2. List<Uint8List> prevOutScripts,
  3. List<int> values,
  4. int hashType,
  5. Uint8List? leafHash,
  6. Uint8List? annex,
)

Implementation

Uint8List hashForWitnessV1(int inIndex, List<Uint8List> prevOutScripts,
    List<int> values, int hashType, Uint8List? leafHash, Uint8List? annex) {
  final outputType = hashType == SIGHASH_DEFAULT
      ? SIGHASH_ALL
      : hashType & SIGHASH_OUTPUT_MASK;
  final inputType = hashType & SIGHASH_INPUT_MASK;
  final isAnyoneCanPay = inputType == SIGHASH_ANYONECANPAY;
  final isNone = outputType == SIGHASH_NONE;
  final isSingle = outputType == SIGHASH_SINGLE;

  var hashPrevouts = Uint8List.fromList([]);
  var hashAmounts = Uint8List.fromList([]);
  var hashScriptPubKeys = Uint8List.fromList([]);
  var hashSequences = Uint8List.fromList([]);
  var hashOutputs = Uint8List.fromList([]);

  if (!isAnyoneCanPay) {
    // Hash txid.
    final hashBuf = Buffer(36 * ins.length);

    for (var txIn in ins) {
      hashBuf.writeSlice(txIn.hash);
      hashBuf.writeUInt32(txIn.index);
    }

    hashPrevouts = hashBuf.toSha256();

    // Hash value.
    final valueBuf = Buffer(8 * ins.length);

    for (var value in values) {
      valueBuf.writeUInt64(value);
    }
    hashAmounts = valueBuf.toSha256();

    // Hash prevout script.
    final scriptBuf =
        Buffer(prevOutScripts.map(varSliceSize).reduce((a, b) => a + b));
    for (var prevOutScript in prevOutScripts) {
      scriptBuf.writeVarSlice(prevOutScript);
    }
    hashScriptPubKeys = scriptBuf.toSha256();

    // Hash sequence.
    final sequenceBuf = Buffer(4 * ins.length);

    for (var txIn in ins) {
      sequenceBuf.writeUInt32(txIn.sequence);
    }
    hashSequences = sequenceBuf.toSha256();
  }

  if (!(isNone || isSingle)) {
    final txOutsSize = outs
        .map((output) => 8 + varSliceSize(output.script!))
        .reduce((a, b) => a + b);
    final outBuf = Buffer(txOutsSize);

    for (var out in outs) {
      outBuf.writeUInt64(out.value);
      outBuf.writeVarSlice(out.script);
    }

    hashOutputs = outBuf.toSha256();
  } else if (isSingle && inIndex < outs.length) {
    final output = outs[inIndex];
    final outBuf = Buffer(8 + varSliceSize(output.script!));

    outBuf.writeUInt64(output.value);
    outBuf.writeVarSlice(output.script);
    hashOutputs = outBuf.toSha256();
  }

  final spendType = (leafHash != null ? 2 : 0) + (annex != null ? 1 : 0);
  final sigMsgSize = 174 -
      (isAnyoneCanPay ? 49 : 0) -
      (isNone ? 32 : 0) +
      (annex != null ? 32 : 0) +
      (leafHash != null ? 37 : 0);
  final buf = Buffer(sigMsgSize);

  buf.writeUInt8(hashType);
  // Transaction
  buf.writeInt32(version);
  buf.writeUInt32(locktime);
  buf.writeSlice(hashPrevouts);
  buf.writeSlice(hashAmounts);
  buf.writeSlice(hashScriptPubKeys);
  buf.writeSlice(hashSequences);

  if (!(isNone || isSingle)) buf.writeSlice(hashOutputs);

  // Input
  buf.writeUInt8(spendType);
  if (isAnyoneCanPay) {
    final input = ins[inIndex];
    buf.writeSlice(input.hash);
    buf.writeUInt32(input.index);
    buf.writeUInt64(values[inIndex]);
    buf.writeVarSlice(prevOutScripts[inIndex]);
    buf.writeUInt32(input.sequence);
  } else {
    buf.writeUInt32(inIndex);
  }

  if (annex != null) {
    final annexBuf = Buffer(varSliceSize(annex));

    annexBuf.writeVarSlice(annex);
    buf.writeSlice(annexBuf.toSha256());
  }
  // Output
  if (isSingle) buf.writeSlice(hashOutputs);

  // BIP342 extension
  if (leafHash != null) {
    buf.writeSlice(leafHash);
    buf.writeUInt8(0);
    buf.writeUInt32(0xffffffff);
  }
  // Extra zero byte because:
  // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
  return Uint8List.fromList(
      bscript.taggedHash('TapSighash', [0x00] + buf.tBuffer));
}