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