signSchnorrTransaction method
Signs a given Schnorr-based transaction digest using the Schnorr signature scheme.
Implementation
List<int> signSchnorrTransaction(List<int> digest,
{required List<dynamic> tapScripts, required bool tweak}) {
if (digest.length != 32) {
throw const ArgumentException("The message must be a 32-byte array.");
}
List<int> byteKey = <int>[];
if (tweak) {
final t = P2TRUtils.calculateTweek(verifyKey.verifyKey.publicKey.point,
script: tapScripts);
byteKey = BitcoinSignerUtils.calculatePrivateTweek(
signingKey.privateKey.toBytes(), BigintUtils.fromBytes(t));
} else {
byteKey = signingKey.privateKey.toBytes();
}
final List<int> aux = QuickCrypto.sha256Hash(<int>[...digest, ...byteKey]);
final d0 = BigintUtils.fromBytes(byteKey);
if (!(BigInt.one <= d0 && d0 <= BitcoinSignerUtils._order - BigInt.one)) {
throw const ArgumentException(
"The secret key must be an integer in the range 1..n-1.");
}
final P = Curves.generatorSecp256k1 * d0;
BigInt d = d0;
if (P.y.isOdd) {
d = BitcoinSignerUtils._order - d;
}
final t = BytesUtils.xor(
BigintUtils.toBytes(d, length: BitcoinSignerUtils.baselen),
P2TRUtils.taggedHash("BIP0340/aux", aux));
final kHash = P2TRUtils.taggedHash(
"BIP0340/nonce",
<int>[
...t,
...BigintUtils.toBytes(P.x, length: BitcoinSignerUtils.baselen),
...digest
],
);
final k0 = BigintUtils.fromBytes(kHash) % BitcoinSignerUtils._order;
if (k0 == BigInt.zero) {
throw const MessageException(
'Failure. This happens only with negligible probability.');
}
final R = (Curves.generatorSecp256k1 * k0);
BigInt k = k0;
if (R.y.isOdd) {
k = BitcoinSignerUtils._order - k;
}
final eHash = P2TRUtils.taggedHash(
"BIP0340/challenge",
List<int>.from([
...BigintUtils.toBytes(R.x, length: BitcoinSignerUtils.baselen),
...BigintUtils.toBytes(P.x, length: BitcoinSignerUtils.baselen),
...digest
]),
);
final e = BigintUtils.fromBytes(eHash) % BitcoinSignerUtils._order;
final eKey = (k + e * d) % BitcoinSignerUtils._order;
final sig = List<int>.from([
...BigintUtils.toBytes(R.x, length: BitcoinSignerUtils.baselen),
...BigintUtils.toBytes(eKey, length: BitcoinSignerUtils.baselen)
]);
final verify = verifyKey.verifySchnorr(digest, sig,
tapleafScripts: tapScripts, isTweak: tweak);
if (!verify) {
throw const MessageException(
'The created signature does not pass verification.');
}
return sig;
}