Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        public bool Verify(ECXOnlyPubKey pubKey, MusigPubNonce pubNonce, MusigPartialSignature partialSignature)
        {
            if (partialSignature == null)
            {
                throw new ArgumentNullException(nameof(partialSignature));
            }
            if (pubNonce == null)
            {
                throw new ArgumentNullException(nameof(pubNonce));
            }
            if (pubKey == null)
            {
                throw new ArgumentNullException(nameof(pubKey));
            }
            if (SessionCache is null)
            {
                throw new InvalidOperationException("You need to run MusigContext.Process first");
            }
            GEJ       pkj;
            Span <GE> nonces = stackalloc GE[2];
            GEJ       rj;
            GEJ       tmp;
            GE        pkp;
            var       b           = SessionCache.NonceCoeff;
            var       pre_session = this;

            /* Compute "effective" nonce rj = nonces[0] + b*nonces[1] */
            /* TODO: use multiexp */

            nonces[0] = pubNonce.K1.Q;
            nonces[1] = pubNonce.K2.Q;

            rj = nonces[1].ToGroupElementJacobian();
            rj = this.ctx.EcMultContext.Mult(rj, b, null);
            rj = rj.AddVariable(nonces[0]);

            pkp = pubKey.Q;

            /* Multiplying the messagehash by the musig coefficient is equivalent
             * to multiplying the signer's public key by the coefficient, except
             * much easier to do. */
            var mu = ECXOnlyPubKey.secp256k1_musig_keyaggcoef(pre_session, pkp.x);
            var e  = SessionCache.Challenge * mu;

            /* If the MuSig-combined point has an odd Y coordinate, the signers will
             * sign for the negation of their individual xonly public key such that the
             * combined signature is valid for the MuSig aggregated xonly key. If the
             * MuSig-combined point was tweaked then `e` is negated if the combined key
             * has an odd Y coordinate XOR the internal key has an odd Y coordinate.*/
            if (pre_session.pk_parity
                != (pre_session.is_tweaked &&
                    pre_session.internal_key_parity))
            {
                e = e.Negate();
            }

            var s = partialSignature.E;

            /* Compute -s*G + e*pkj + rj */
            s   = s.Negate();
            pkj = pkp.ToGroupElementJacobian();
            tmp = ctx.EcMultContext.Mult(pkj, e, s);
            var fin_nonce_parity = SessionCache.FinalNonceParity;

            if (fin_nonce_parity)
            {
                rj = rj.Negate();
            }
            tmp = tmp.AddVariable(rj);
            return(tmp.IsInfinity);
        }