signBip340 method
Implementation
List<int> signBip340({
required List<int> digest,
List<int>? tapTweakHash,
List<int>? aux,
}) {
if (digest.length != BitcoinSignerUtils.baselen) {
throw ArgumentException.invalidOperationArguments(
"signBip340",
name: 'digest',
reason: "Invalid digest bytes length.",
);
}
if (aux != null && aux.length != 32) {
throw ArgumentException.invalidOperationArguments(
"signBip340",
name: 'aux',
reason: "Invalid aux bytes length.",
);
}
List<int> byteKey = <int>[];
if (tapTweakHash != null) {
byteKey = BitcoinSignerUtils.calculatePrivateTweek(
privateKey.toBytes(),
tapTweakHash,
);
} else {
byteKey = privateKey.toBytes();
}
aux ??= QuickCrypto.sha256Hash(<int>[...digest, ...byteKey]);
final d0 = BigintUtils.fromBytes(byteKey);
if (!(BigInt.one <= d0 && d0 <= BitcoinSignerUtils.order - BigInt.one)) {
throw ArgumentException.invalidOperationArguments(
"signBip340",
reason: "Invalid signing key.",
);
}
final P = BitcoinSignerUtils.generator * 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 CryptoSignException(
'Signing failed due to an unexpected error.',
);
}
final R = (BitcoinSignerUtils.generator * k0);
BigInt k = k0;
if (R.y.isOdd) {
k = BitcoinSignerUtils.order - k;
}
final eHash = P2TRUtils.taggedHash("BIP0340/challenge", [
...R.toXonly(),
...P.toXonly(),
...digest,
]);
final e = BigintUtils.fromBytes(eHash) % BitcoinSignerUtils.order;
final eKey = (k + e * d) % BitcoinSignerUtils.order;
return [
...R.toXonly(),
...BigintUtils.toBytes(eKey, length: BitcoinSignerUtils.baselen),
];
}