signBip340Const method

List<int> signBip340Const({
  1. required List<int> digest,
  2. List<int>? tapTweakHash,
  3. List<int>? aux,
})

Implementation

List<int> signBip340Const({
  required List<int> digest,
  List<int>? tapTweakHash,
  List<int>? aux,
}) {
  if (digest.length != BitcoinSignerUtils.baselen) {
    throw ArgumentException.invalidOperationArguments(
      "signBip340Const",
      name: "digest",
      reason: "Invalid digest bytes length.",
    );
  }
  if (aux != null && aux.length != 32) {
    throw ArgumentException.invalidOperationArguments(
      "signBip340Const",
      name: "aux",
      reason: "Invalid aux bytes length.",
    );
  }

  final tKey = _tweakConst(
    privateKey.toBytes(),
    ecMultContext,
    tapTweakHash: tapTweakHash,
  );
  aux ??= QuickCrypto.sha256Hash([
    ...digest,
    ...Secp256k1Utils.scalarToBytes(tKey),
  ]);

  Secp256k1Ge mid = Secp256k1Ge();
  Secp256k1Gej res = Secp256k1Gej();
  Secp256k1.secp256k1ECmultGen(ecMultContext, res, tKey);
  Secp256k1.secp256k1GeSetGej(mid, res);
  if (Secp256k1.secp256k1FeIsOdd(mid.y) == 1) {
    Secp256k1.secp256k1ScalarNegate(tKey, tKey);
  }
  final d = Secp256k1Utils.scalarToBytes(tKey);
  final t = BytesUtils.xor(d, P2TRUtils.taggedHash("BIP0340/aux", aux));
  Secp256k1.secp256k1FeNormalize(mid.x);
  final xBytes = Secp256k1Utils.feToBytes(mid.x);

  final kHash = P2TRUtils.taggedHash("BIP0340/nonce", [
    ...t,
    ...xBytes,
    ...digest,
  ]);
  final k0 = Secp256k1Utils.scalarFromBytes(kHash);

  if (!Secp256k1Utils.scCheck(k0)) {
    throw const CryptoSignException(
      'Schnorr signing failed due to an unexpected error.',
    );
  }
  Secp256k1Ge midR = Secp256k1Ge();
  Secp256k1Gej resR = Secp256k1Gej();
  Secp256k1.secp256k1ECmultGen(ecMultContext, resR, k0);
  Secp256k1.secp256k1GeSetGej(midR, resR);

  if (Secp256k1.secp256k1FeIsOdd(midR.y) == 1) {
    Secp256k1.secp256k1ScalarNegate(k0, k0);
  }
  Secp256k1.secp256k1FeNormalize(midR.x);
  final rBytes = Secp256k1Utils.feToBytes(midR.x);
  final eHash = P2TRUtils.taggedHash("BIP0340/challenge", [
    ...rBytes,
    ...xBytes,
    ...digest,
  ]);
  final eSclar = Secp256k1Utils.scalarFromBytes(eHash);
  if (!Secp256k1Utils.scCheck(eSclar)) {
    throw const CryptoSignException(
      'Schnorr signing failed due to an unexpected error.',
    );
  }
  Secp256k1Scalar n = Secp256k1Scalar();
  Secp256k1Scalar sigs = Secp256k1Scalar();
  Secp256k1.secp256k1ScalarMul(n, eSclar, tKey);
  Secp256k1.secp256k1ScalarAdd(sigs, k0, n);
  if (!Secp256k1Utils.scCheck(sigs)) {
    throw const CryptoSignException(
      'Schnorr signing failed due to an unexpected error.',
    );
  }
  List<int> sBytes = List<int>.filled(32, 0);
  Secp256k1.secp256k1ScalarGetB32(sBytes, sigs);

  return [...rBytes, ...sBytes];
}