verify method

  1. @override
bool verify()
override

Implementation

@override
bool verify() {
  final psbtInputs = txData.psbt.inputs;
  if (psbtInputs.isEmpty) return false;

  final List<_Prevout> prevouts;
  try {
    prevouts = _gatherPrevouts();
  } catch (_) {
    return false;
  }
  final prevOutScripts = prevouts.map((p) => p.scriptHex).toList();
  final prevOutValues = prevouts.map((p) => p.value).toList();

  for (int i = 0; i < psbtInputs.length; i++) {
    final input = psbtInputs[i];

    if (txData.isTaproot) {
      final sig = input.taprootKeySpendSignature;
      final outputKey = prevouts[i].taprootOutputKey;
      if (sig == null || outputKey == null) return false;

      final Uint8List signatureBytes;
      try {
        signatureBytes = fromHex(sig);
      } catch (_) {
        return false;
      }
      if (signatureBytes.length != 64 && signatureBytes.length != 65) {
        return false;
      }

      final signatureHashType =
          signatureBytes.length == 65 ? signatureBytes.last : 0x00;
      if (!_validTaprootSighashTypes.contains(signatureHashType) ||
          (signatureBytes.length == 65 && signatureHashType == 0x00) ||
          (input.sighashType != null &&
              input.sighashType != signatureHashType)) {
        return false;
      }

      final String sigHashHex;
      try {
        sigHashHex = txData.psbt.unsignedTransaction!.getTaprootSigHash(
          i,
          prevOutScripts,
          prevOutValues,
          hashType: signatureHashType,
        );
      } catch (_) {
        return false;
      }
      final rawSignature =
          dynamicToString(signatureBytes.sublist(0, 64));
      try {
        if (!Schnorr.verify(outputKey, rawSignature, sigHashHex)) return false;
      } catch (_) {
        return false;
      }
    } else {
      final partialSigs = input.partialSigs;
      if (partialSigs == null || partialSigs.length != 2) return false;
      final signature = partialSigs[0];
      final Uint8List signatureBytes;
      final Uint8List publicKey;
      try {
        signatureBytes = fromHex(signature);
        publicKey = fromHex(partialSigs[1]);
      } catch (_) {
        return false;
      }
      if (signatureBytes.isEmpty || signatureBytes.last != 0x01) {
        return false;
      }
      final expectedPublicKeyHash = prevouts[i].p2pkhPublicKeyHash;
      if (expectedPublicKeyHash == null ||
          dynamicToString(sha160fromByte(publicKey)) !=
              dynamicToString(expectedPublicKeyHash)) {
        return false;
      }

      final sigHashHex = txData.psbt.unsignedTransaction!.getSigHash(
        i,
        prevouts[i].fullOutputHex,
        false,
      );
      if (!EcdaSignature.verifyDerWithHashType(
          sigHashHex, publicKey, signature)) {
        return false;
      }
    }
  }
  return true;
}