sign method

  1. @override
List<int> sign({
  1. required List<int> secnonce,
  2. required List<int> sk,
  3. required MuSig2Session session,
})
override

Generates a MuSig2 partial signature

Implementation

@override
List<int> sign({
  required List<int> secnonce,
  required List<int> sk,
  required MuSig2Session session,
}) {
  if (secnonce.length != MuSig2Constants.secnoncelength) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "secnonce",
      reason: "Invalid secret nonce bytes length.",
      expecteLen: MuSig2Constants.secnoncelength,
    );
  }
  final values = MuSig2Utils.decodeSession(session);
  BigInt k1 = BigintUtils.fromBytes(
    secnonce.sublist(0, MuSig2Constants.xOnlyBytesLength),
  );
  BigInt k2 = BigintUtils.fromBytes(
    secnonce.sublist(
      MuSig2Constants.xOnlyBytesLength,
      MuSig2Constants.xOnlyBytesLength * 2,
    ),
  );
  if (k1 <= BigInt.zero || k1 >= MuSig2Constants.order) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "secnonce",
      reason: "Invalid secret nonce.",
    );
  }
  if (k2 <= BigInt.zero || k2 >= MuSig2Constants.order) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "secnonce",
      reason: "Invalid secret nonce.",
    );
  }
  BigInt kE1 = k1;
  BigInt kE2 = k2;
  if (values.r.isOdd) {
    kE1 = MuSig2Constants.order - k1;
    kE2 = MuSig2Constants.order - k2;
  }

  BigInt d = BigintUtils.fromBytes(sk);
  if (d <= BigInt.zero || d >= MuSig2Constants.order) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "sk",
      reason: "Invalid secret key.",
    );
  }
  final p = MuSig2Constants.generator * d;
  final pkBytes = p.toBytes();
  final pkOffset = MuSig2Constants.xOnlyBytesLength * 2;
  if (!BytesUtils.bytesEqual(
    secnonce.sublist(
      pkOffset,
      pkOffset + EcdsaKeysConst.pubKeyCompressedByteLen,
    ),
    pkBytes,
  )) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      reason: "Missmatch between secret key and public key.",
    );
  }
  final a = MuSig2Utils.getSessionKeyAggCoeff(session: session, pk: p);
  BigInt g = BigInt.one;
  if (values.publicKey.isOdd) {
    g = MuSig2Constants.order - BigInt.one;
  }
  d = g * values.gaccAsInteger * d % MuSig2Constants.order;
  final s =
      (kE1 + values.bAsInteger * kE2 + values.eAsInteger * a * d) %
      MuSig2Constants.order;
  final sig = BigintUtils.toBytes(s).toImutableBytes;
  final rS1 = MuSig2Constants.generator * k1;
  final rS2 = MuSig2Constants.generator * k2;
  final List<int> pubnonce = [...rS1.toBytes(), ...rS2.toBytes()];
  final verify = partialSigVerify(
    signature: sig,
    pubnonce: pubnonce,
    pk: pkBytes,
    session: session,
  );
  if (!verify) {
    throw CryptoSignException.signatureVerificationFailed;
  }
  return sig;
}