signTransaction method
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;
}