signTransaction method

List<int> signTransaction(
  1. List<int> digest
)

Signs a given transaction digest using the ECDSA deterministic signature scheme. The signature is adjusted for low-S encoding and verified against the public key.

Implementation

List<int> signTransaction(List<int> digest) {
  ECDSASignature ecdsaSign = signingKey.signDigestDeterminstic(
      digest: digest, hashFunc: () => SHA256());
  List<int> signature = BigintUtils.toDer([ecdsaSign.r, ecdsaSign.s]);

  int attempt = 1;
  int lengthR = signature[3];

  while (lengthR == 33) {
    final List<int> extraEntropy = List<int>.filled(32, 0);
    final attemptBytes =
        IntUtils.toBytes(attempt, length: IntUtils.bitlengthInBytes(attempt));
    extraEntropy.setAll(
        extraEntropy.length - attemptBytes.length, attemptBytes);

    ecdsaSign = signingKey.signDigestDeterminstic(
        digest: digest, hashFunc: () => SHA256(), extraEntropy: extraEntropy);

    signature = BigintUtils.toDer([ecdsaSign.r, ecdsaSign.s]);
    attempt += 1;
    lengthR = signature[3];
  }

  final int derPrefix = signature[0];
  int lengthTotal = signature[1];
  final int derTypeInt = signature[2];
  final List<int> R = signature.sublist(4, 4 + lengthR);
  int lengthS = signature[5 + lengthR];
  final List<int> S = signature.sublist(5 + lengthR + 1);
  final BigInt sAsBigint = BigintUtils.fromBytes(S);
  List<int> newS;
  if (lengthS == 33) {
    final newSAsBigint = BitcoinSignerUtils._order - sAsBigint;
    newS =
        BigintUtils.toBytes(newSAsBigint, length: BitcoinSignerUtils.baselen);
    lengthS -= 1;
    lengthTotal -= 1;
  } else {
    newS = S;
  }

  signature = List<int>.from([
    derPrefix,
    lengthTotal,
    derTypeInt,
    lengthR,
    ...R,
    derTypeInt,
    lengthS,
    ...newS,
  ]);

  final verify = verifyKey.verifyTransaction(digest, signature);
  if (!verify) {
    throw const MessageException(
        'The created signature does not pass verification.');
  }
  return signature;
}