internal static void secp256k1_musig_nonce_process_internal( ECMultContext ecmult_ctx, out bool fin_nonce_parity, Span <byte> fin_nonce, out Scalar b, Span <GEJ> aggnoncej, ReadOnlySpan <byte> agg_pk32, ReadOnlySpan <byte> msg) { Span <byte> noncehash = stackalloc byte[32]; Span <GE> aggnonce = stackalloc GE[2]; aggnonce[0] = aggnoncej[0].ToGroupElement(); aggnonce[1] = aggnoncej[1].ToGroupElement(); secp256k1_musig_compute_noncehash(noncehash, aggnonce, agg_pk32, msg); /* aggnonce = aggnonces[0] + b*aggnonces[1] */ b = new Scalar(noncehash); var fin_nonce_ptj = ecmult_ctx.Mult(aggnoncej[1], b, null); fin_nonce_ptj = fin_nonce_ptj.Add(aggnonce[0]); var fin_nonce_pt = fin_nonce_ptj.ToGroupElement(); ECXOnlyPubKey.secp256k1_xonly_ge_serialize(fin_nonce, ref fin_nonce_pt); fin_nonce_pt = fin_nonce_pt.NormalizeYVariable(); fin_nonce_parity = fin_nonce_pt.y.IsOdd; }
internal static void secp256k1_musig_compute_noncehash(Span <byte> noncehash, Span <GE> summed_nonces, ReadOnlySpan <byte> combined_pk32, ReadOnlySpan <byte> msg) { Span <byte> buf = stackalloc byte[32]; using SHA256 sha = new SHA256(); sha.Initialize(); int i; for (i = 0; i < 2; i++) { ECXOnlyPubKey.secp256k1_xonly_ge_serialize(buf, ref summed_nonces[i]); sha.Write(buf); } sha.Write(combined_pk32.Slice(0, 32)); sha.Write(msg.Slice(0, 32)); sha.GetHash(noncehash); }
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; }