public PublicKey DerivePublickey(PublicKey basepoint, PublicKey perCommitmentPoint)
        {
            // TODO: pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G

            Span <byte> toHash = stackalloc byte[PublicKey.LENGTH * 2];

            perCommitmentPoint.GetSpan().CopyTo(toHash);
            basepoint.GetSpan().CopyTo(toHash.Slice(PublicKey.LENGTH));
            byte[] hashed = NBitcoin.Crypto.Hashes.SHA256(toHash);

            if (ECPubKey.TryCreate(basepoint, Context.Instance, out _, out ECPubKey? ecpubkey))
            {
                if (ecpubkey.TryAddTweak(hashed.AsSpan(), out ECPubKey? ecpubkeytweaked))
                {
                    if (ecpubkeytweaked != null)
                    {
                        Span <byte> pub = stackalloc byte[33];
                        ecpubkeytweaked.WriteToSpan(true, pub, out _);
                        return(new PublicKey(pub.ToArray()));
                    }
                }
            }

            return(null);
        }
        public PublicKey DeriveRevocationPublicKey(PublicKey basepoint, PublicKey perCommitmentPoint)
        {
            // TODO: revocationpubkey = revocation_basepoint * SHA256(revocation_basepoint || per_commitment_point) + per_commitment_point * SHA256(per_commitment_point || revocation_basepoint)

            Span <byte> toHash1 = stackalloc byte[PublicKey.LENGTH * 2];

            basepoint.GetSpan().CopyTo(toHash1);
            perCommitmentPoint.GetSpan().CopyTo(toHash1.Slice(PublicKey.LENGTH));
            byte[] hashed1 = NBitcoin.Crypto.Hashes.SHA256(toHash1);

            ECPubKey?revocationBasepointTweaked = null;

            if (ECPubKey.TryCreate(basepoint, Context.Instance, out _, out ECPubKey? ecbasepoint))
            {
                if (ecbasepoint.TryMultTweak(hashed1.AsSpan(), out ECPubKey? ecpubkeytweaked))
                {
                    if (ecpubkeytweaked != null)
                    {
                        revocationBasepointTweaked = ecpubkeytweaked;
                    }
                }
            }

            Span <byte> toHash2 = stackalloc byte[PublicKey.LENGTH * 2];

            perCommitmentPoint.GetSpan().CopyTo(toHash2);
            basepoint.GetSpan().CopyTo(toHash2.Slice(PublicKey.LENGTH));
            byte[] hashed2 = NBitcoin.Crypto.Hashes.SHA256(toHash2);

            ECPubKey?perCommitmentPointTweaked = null;

            if (ECPubKey.TryCreate(perCommitmentPoint, Context.Instance, out _, out ECPubKey? ecperCommitmentPoint))
            {
                if (ecperCommitmentPoint.TryMultTweak(hashed2.AsSpan(), out ECPubKey? ecperCommitmentPointtweaked))
                {
                    if (ecperCommitmentPointtweaked != null)
                    {
                        perCommitmentPointTweaked = ecperCommitmentPointtweaked;
                    }
                }
            }

            if (revocationBasepointTweaked != null && perCommitmentPointTweaked != null)
            {
                var keys = new ECPubKey[] { revocationBasepointTweaked, perCommitmentPointTweaked };

                if (ECPubKey.TryCombine(Context.Instance, keys, out ECPubKey? revocationpubkey))
                {
                    if (revocationpubkey != null)
                    {
                        Span <byte> pub = stackalloc byte[33];
                        revocationpubkey.WriteToSpan(true, pub, out _);
                        return(new PublicKey(pub.ToArray()));
                    }
                }
            }

            return(null);
        }
 public MusigPubNonce(Context?context, ReadOnlySpan <byte> in66)
 {
     if (!ECPubKey.TryCreate(in66.Slice(0, 33), context, out _, out var k1) ||
         !ECPubKey.TryCreate(in66.Slice(33, 33), context, out _, out var k2))
     {
         throw new ArgumentException("Invalid musig pubnonce");
     }
     this.context = context ?? Context.Instance;
     this.k1      = k1;
     this.k2      = k2;
 }