signBip340 method

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

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),
  ];
}