public MusigPrivNonce GenerateNonce(ReadOnlySpan <byte> sessionId32, ECPrivKey?signingKey, ReadOnlySpan <byte> extraInput32)
 {
     return(MusigPrivNonce.GenerateMusigNonce(ctx, sessionId32, signingKey, this.msg32, this.aggregatePubKey, extraInput32));
 }
        public MusigPartialSignature Sign(ECPrivKey privKey, MusigPrivNonce privNonce)
        {
            if (privKey == null)
            {
                throw new ArgumentNullException(nameof(privKey));
            }
            if (privNonce == null)
            {
                throw new ArgumentNullException(nameof(privNonce));
            }
            if (privNonce.IsUsed)
            {
                throw new ArgumentNullException(nameof(privNonce), "Nonce already used, a nonce should never be used to sign twice");
            }
            if (SessionCache is null)
            {
                throw new InvalidOperationException("You need to run MusigContext.Process first");
            }

            //{
            //	/* Check in constant time if secnonce has been zeroed. */
            //	size_t i;
            //	unsigned char secnonce_acc = 0;
            //	for (i = 0; i < sizeof(*secnonce) ; i++) {
            //		secnonce_acc |= secnonce->data[i];
            //	}
            //	secp256k1_declassify(ctx, &secnonce_acc, sizeof(secnonce_acc));
            //	ARG_CHECK(secnonce_acc != 0);
            //}

            var           pre_session   = this;
            var           session_cache = SessionCache;
            Span <Scalar> k             = stackalloc Scalar[2];

            k[0] = privNonce.K1.sec;
            k[1] = privNonce.K2.sec;


            /* Obtain the signer's public key point and determine if the sk is
             * negated before signing. That happens if if the signer's pubkey has an odd
             * Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR
             * (if tweaked) the internal key has an odd Y coordinate.
             *
             * This can be seen by looking at the sk key belonging to `combined_pk`.
             * Let's define
             * P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
             * point x_i*G, mu_i is the i-th musig coefficient and |.| is a function
             * that normalizes a point to an even Y by negating if necessary similar to
             * secp256k1_extrakeys_ge_even_y. Then we have
             * P := |P'| + t*G where t is the tweak.
             * And the combined xonly public key is
             * |P| = x*G
             *      where x = sum_i(b_i*mu_i*x_i) + b'*t
             *            b' = -1 if P != |P|, 1 otherwise
             *            b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) and 1
             *                otherwise.
             */

            var sk = privKey.sec;
            var pk = privKey.CreatePubKey().Q;

            pk = pk.NormalizeYVariable();

            int l = 0;

            if (pk.y.IsOdd)
            {
                l++;
            }
            if (pre_session.pk_parity)
            {
                l++;
            }
            if (pre_session.internal_key_parity)
            {
                l++;
            }
            if (l % 2 == 1)
            {
                sk = sk.Negate();
            }

            /* Multiply MuSig coefficient */
            pk = pk.NormalizeXVariable();
            var mu = ECXOnlyPubKey.secp256k1_musig_keyaggcoef(pre_session, pk.x);

            sk = sk * mu;
            if (session_cache.FinalNonceParity)
            {
                k[0] = k[0].Negate();
                k[1] = k[1].Negate();
            }

            var e = session_cache.Challenge * sk;

            k[1] = session_cache.NonceCoeff * k[1];
            k[0] = k[0] + k[1];
            e    = e + k[0];
            Scalar.Clear(ref k[0]);
            Scalar.Clear(ref k[1]);
            privNonce.IsUsed = true;
            return(new MusigPartialSignature(e));
        }