signSchnorr method
Signs the given transaction digest using Schnorr signature (old style).
This method is primarily useful for networks like Bitcoin Cash (BCH) that support Schnorr signatures in a legacy format.
digest: The transaction digest (message) to sign.
Implementation
List<int> signSchnorr(List<int> digest, {List<int>? extraEntropy}) {
if (digest.length != BitcoinSignerUtils.baselen) {
throw CryptoSignException(
"The digest must be a ${BitcoinSignerUtils.baselen}-byte array.");
}
BigInt d = _signingKey.privateKey.secretMultiplier;
final BigInt order = CryptoSignerConst.generatorSecp256k1.order!;
if (!(BigInt.one <= d && d <= order - BigInt.one)) {
throw const CryptoSignException(
"The secret key must be an integer in the range 1..n-1.");
}
extraEntropy ??= CryptoSignerConst.bchSchnorrRfc6979ExtraData;
BigInt k = RFC6979.generateK(
order: order,
secexp: _signingKey.privateKey.secretMultiplier,
hashFunc: () => SHA256(),
data: digest,
extraEntropy: extraEntropy);
final R = (CryptoSignerConst.generatorSecp256k1 * k);
if (ECDSAUtils.jacobi(R.y, CryptoSignerConst.curveSecp256k1.p).isNegative) {
k = order - k;
}
// Step 4: Compute e = SHA256(R || pubkey || digest)
final eHash = QuickCrypto.sha256Hash([
...R.toXonly(),
...verifierKey._verifyKey.publicKey.toBytes(),
...digest
]);
final BigInt e = BigintUtils.fromBytes(eHash) % order;
// Step 5: Compute Schnorr Signature: s = k + e * d (mod n)
final BigInt s = (k + e * d) % order;
final signature = BitcoinSchnorrSignature(r: R.x, s: s).toBytes();
final verify = verifierKey.verifySchnorrSignature(
digest: digest, signature: signature);
if (!verify) {
throw const CryptoSignException(
'The created signature does not pass verification.');
}
// Step 6: Return Signature (64 bytes: R.x || s)
return signature;
}