public void Process(MusigPubNonce aggregatedNonce) { if (processed_nonce) { throw new InvalidOperationException($"Nonce already processed"); } var agg_pk = this.SigningPubKey; MusigSessionCache session_cache = new MusigSessionCache(); Span <byte> fin_nonce = stackalloc byte[32]; Span <byte> agg_pk32 = stackalloc byte[32]; Span <GEJ> aggnonce_ptj = stackalloc GEJ[2]; aggnonce_ptj[0] = aggregatedNonce.K1.Q.ToGroupElementJacobian(); aggnonce_ptj[1] = aggregatedNonce.K2.Q.ToGroupElementJacobian(); agg_pk.WriteToSpan(agg_pk32); /* Add public adaptor to nonce */ if (adaptor != null) { aggnonce_ptj[0] = aggnonce_ptj[0].AddVariable(adaptor.Q); } secp256k1_musig_nonce_process_internal(this.ctx.EcMultContext, out session_cache.FinalNonceParity, fin_nonce, out session_cache.NonceCoeff, aggnonce_ptj, agg_pk32, msg32); /* Compute messagehash and store in session cache */ ECXOnlyPubKey.secp256k1_schnorrsig_challenge(out session_cache.Challenge, fin_nonce, msg32, agg_pk32); /* If there is a tweak then set `msghash` times `tweak` to the `s`-part of the sig template.*/ session_cache.SPart = Scalar.Zero; if (is_tweaked) { Scalar e_tmp = session_cache.Challenge; if (!ECPrivKey.secp256k1_eckey_privkey_tweak_mul(ref e_tmp, scalar_tweak)) { throw new InvalidOperationException("Impossible to sign (secp256k1_eckey_privkey_tweak_mul is false)"); } if (pk_parity) { e_tmp = e_tmp.Negate(); } session_cache.SPart = session_cache.SPart.Add(e_tmp); } fin_nonce.CopyTo(session_cache.FinalNonce); SessionCache = session_cache; processed_nonce = true; this.aggregateNonce = aggregatedNonce; }
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); }
public void Process(MusigPubNonce combinedNonce) { if (processed_nonce) { throw new InvalidOperationException($"Nonce already processed"); } var combined_pk = this.SigningPubKey; MusigSessionCache session_cache = new MusigSessionCache(); Span <byte> noncehash = stackalloc byte[32]; Span <byte> sig_template_data = stackalloc byte[32]; Span <byte> combined_pk32 = stackalloc byte[32]; Span <GEJ> summed_nonces = stackalloc GEJ[2]; summed_nonces[0] = combinedNonce.K1.Q.ToGroupElementJacobian(); summed_nonces[1] = combinedNonce.K2.Q.ToGroupElementJacobian(); combined_pk.WriteToSpan(combined_pk32); /* Add public adaptor to nonce */ if (adaptor != null) { summed_nonces[0] = summed_nonces[0].AddVariable(adaptor.Q); } var combined_nonce = secp256k1_musig_process_nonces_internal( this.ctx.EcMultContext, noncehash, summed_nonces, combined_pk32, msg32); session_cache.B = new Scalar(noncehash); ECXOnlyPubKey.secp256k1_xonly_ge_serialize(sig_template_data, ref combined_nonce); var rx = combined_nonce.x; /* Negate nonce if Y coordinate is not square */ combined_nonce = combined_nonce.NormalizeYVariable(); /* Store nonce parity in session cache */ session_cache.CombinedNonceParity = combined_nonce.y.IsOdd; /* Compute messagehash and store in session cache */ ECXOnlyPubKey.secp256k1_musig_compute_messagehash(noncehash, sig_template_data, combined_pk32, msg32); session_cache.E = new Scalar(noncehash); /* If there is a tweak then set `msghash` times `tweak` to the `s`-part of the sig template.*/ Scalar s = Scalar.Zero; if (is_tweaked) { Scalar e = session_cache.E; if (!ECPrivKey.secp256k1_eckey_privkey_tweak_mul(ref e, scalar_tweak)) { throw new InvalidOperationException("Impossible to sign (secp256k1_eckey_privkey_tweak_mul is false)"); } if (pk_parity) { e = e.Negate(); } s = s.Add(e); } SessionCache = session_cache; Template = new SecpSchnorrSignature(rx, s); processed_nonce = true; this.combinedNonce = combinedNonce; }
public void ProcessNonces(MusigPubNonce[] nonces) { Process(MusigPubNonce.Aggregate(nonces)); }
public void ProcessNonces(MusigPubNonce[] nonces) { Process(MusigPubNonce.Combine(nonces)); }