sign method

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

Generates a MuSig2 partial signature

Implementation

@override
List<int> sign({
  required List<int> secnonce,
  required List<int> sk,
  required MuSig2Session session,
  Secp256k1ECmultGenContext? context,
}) {
  if (secnonce.length != MuSig2Constants.secnoncelength) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "secnonce",
      reason: "Invalid secret nonce bytes length.",
      expecteLen: MuSig2Constants.secnoncelength,
    );
  }
  final values = MuSig2UtilsConst.decodeSessionConst(session);
  final r = Secp256k1Utils.loadPublicKey(values.r.toBytes());
  if (r == null) {
    throw ArgumentException.invalidOperationArguments(
      "signConst",
      name: "r",
      reason: "Invalid session public r public key.",
    );
  }
  final isOdd = Secp256k1.secp256k1FeIsOdd(r.y);
  final k1 = Secp256k1Utils.scalarFromBytes(
    secnonce.sublist(0, MuSig2Constants.xOnlyBytesLength),
  );
  final k2 = Secp256k1Utils.scalarFromBytes(
    secnonce.sublist(
      MuSig2Constants.xOnlyBytesLength,
      MuSig2Constants.xOnlyBytesLength * 2,
    ),
  );
  final k1Scalar = k1.clone();
  final k2Scalar = k2.clone();
  Secp256k1.secp256k1ScalarCondNegate(k1Scalar, isOdd);
  Secp256k1.secp256k1ScalarCondNegate(k2Scalar, isOdd);
  final d = Secp256k1Utils.scalarFromBytes(sk);
  context ??= Secp256k1Utils.initalizeBlindEcMultContext();
  Secp256k1Gej R = Secp256k1Gej();
  Secp256k1.secp256k1ECmultGen(context, R, d);
  Secp256k1Ge mid1 = Secp256k1Utils.secp256k1MultBase(
    scalar: d,
    context: context,
  );
  // Secp256k1.secp256k1GeSetGej(mid1, R);
  final pkBytes = Secp256k1Utils.secp256k1ECkeyPubkeySerialize(mid1, true);
  if (pkBytes == null) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      name: "sk",
      reason: "Invalid secret key.",
    );
  }
  final pkOffset = MuSig2Constants.xOnlyBytesLength * 2;
  if (!BytesUtils.bytesEqualConst(
    secnonce.sublist(
      pkOffset,
      pkOffset + EcdsaKeysConst.pubKeyCompressedByteLen,
    ),
    pkBytes,
  )) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      reason: "Missmatch between secret key and public key.",
    );
  }
  final a = MuSig2Utils.getSessionKeyAggCoeffConst(
    session: session,
    pkBytes: pkBytes,
  );
  final aggPk = Secp256k1Utils.loadPublicKey(values.publicKey.toBytes());
  if (aggPk == null) {
    throw ArgumentException.invalidOperationArguments(
      "sign",
      reason: "Invalid agg public key.",
    );
  }
  Secp256k1Scalar g = Secp256k1Const.secp256k1ScalarOne.clone();
  if (Secp256k1.secp256k1FeIsOdd(aggPk.y) != 0) {
    Secp256k1.secp256k1ScalarNegate(g, g);
  }
  Secp256k1Scalar gcc = Secp256k1Utils.scalarFromBytes(values.gacc);
  Secp256k1Scalar b = Secp256k1Utils.scalarFromBytes(values.b);
  Secp256k1Scalar e = Secp256k1Utils.scalarFromBytes(values.e);
  Secp256k1.secp256k1ScalarMul(g, gcc, g);
  Secp256k1.secp256k1ScalarMul(d, g, d);
  Secp256k1Scalar s1 = Secp256k1Scalar();
  Secp256k1Scalar s2 = Secp256k1Scalar();
  Secp256k1.secp256k1ScalarMul(s1, b, k2Scalar);
  Secp256k1.secp256k1ScalarAdd(s1, s1, k1Scalar);
  Secp256k1.secp256k1ScalarMul(s2, e, a);
  Secp256k1.secp256k1ScalarMul(s2, s2, d);
  Secp256k1.secp256k1ScalarAdd(s1, s1, s2);

  if (Secp256k1.secp256k1ScalarIsZero(s1).toBool) {
    throw const CryptoSignException(
      'Signing failed due to generate signature scalar.',
    );
  }
  final rS1 = Secp256k1Utils.generatePublicKeyBlind(scalar: k1);
  final rS2 = Secp256k1Utils.generatePublicKeyBlind(scalar: k2);
  if (rS1 == null || rS2 == null) {
    throw const CryptoSignException(
      'Signing failed due to generate pubnonce.',
    );
  }
  final signature = Secp256k1Utils.scalarToBytes(
    s1,
    clean: true,
    validate: false,
  );
  final List<int> pubnonce = [...rS1, ...rS2];
  final verify = partialSigVerify(
    signature: signature,
    pubnonce: pubnonce,
    pk: pkBytes,
    session: session,
  );
  if (!verify) {
    throw CryptoSignException.signatureVerificationFailed;
  }
  return signature;
}