verifyXrpSignature function

VerifyResult verifyXrpSignature(
  1. VerifyXrpSignatureArgs args
)

XRP has no request id — this check IS the binding. The signed binary is split into its canonical fields; TxnSignature is removed; the remainder (prefixed with the XRPL signing tag STX\0) is hashed with SHA-512-half and the DER signature is verified against SigningPubKey, which must also equal the key your request carried.

The field walker covers the types Payment-class transactions use; a transaction carrying an exotic field type comes back checked: false rather than a false verdict.

Implementation

VerifyResult verifyXrpSignature(VerifyXrpSignatureArgs args) {
  List<_XrpField> fields;
  try {
    fields = _splitFields(args.signedTx);
  } on _WalkError catch (e) {
    if (e.message == 'unsupported-field') {
      return unverifiable(
          'the transaction carries a field type this checker does not walk');
    }
    return failed('the signed transaction is not readable: ${e.message}');
  }

  _XrpField? signingPubKey;
  _XrpField? txnSignature;
  for (final f in fields) {
    if (f.header == 0x73) signingPubKey ??= f;
    if (f.header == 0x74) txnSignature ??= f;
  }
  if (signingPubKey == null || txnSignature == null) {
    return failed(
        'the signed transaction is missing SigningPubKey or TxnSignature');
  }
  final expected = hexToBytes(args.expectedSigningPubKey);
  if (!equalBytes(signingPubKey.value, expected)) {
    return failed(
      'the transaction was signed with a different key (${bytesToHex(signingPubKey.value)})',
    );
  }

  // Signing payload: every field except TxnSignature, in the original
  // (canonical) order, behind the 'STX\0' prefix; SHA-512 halved.
  final payload = concatBytes([
    Uint8List.fromList([0x53, 0x54, 0x58, 0x00]),
    for (final f in fields)
      if (f.header != 0x74) f.raw,
  ]);
  final digest = Uint8List.sublistView(sha512(payload), 0, 32);

  bool ok;
  try {
    ok = Secp256k1.verify(_derToCompact(txnSignature.value), digest, expected);
  } on Object catch (e) {
    return failed('XRP signature could not be checked: $e');
  }
  return ok
      ? verified
      : failed('the signature does not verify against SigningPubKey');
}