public const int MAX_MESSAGELENGTH_RELAY = 3 + 2 + 16 * 1024; //! bytes (+3 for OP_NOP OP_NOP OP_RETURN, +2 for the pushdata opcodes)

        public Script GenerateScriptPubKey(string message, string messageRecipient, string replyToAddress, string rewardAddress, bool encryptMessage, RsaPublicKey publicKey, RsaPrivateKey privateKey)
        {
            byte[] pushData = null;

            var wsm = new WantedSystemMessage()
            {
                Encryption = (encryptMessage ? MessageEncryption.RSA4096AES256 : MessageEncryption.None),
                Text       = message,
                Metadata   = new WantedSystemMessageMetadata()
                {
                    CreationTimeUtc  = DateTime.UtcNow.ToString(),
                    RecipientAddress = messageRecipient,
                    ReplyToAddress   = replyToAddress,
                    RewardAddress    = rewardAddress
                }
            };

            if (encryptMessage)
            {
                pushData = GenerateWantedSystemMessagePushData(wsm, publicKey);
            }
            else
            {
                pushData = GenerateWantedSystemMessagePushData(wsm);
            }

            return(GenerateScriptPubKey(pushData));
        }
        private byte[] GenerateWantedSystemMessagePushData(WantedSystemMessage message, RsaPublicKey publicKey = null)
        {
            byte[] encryptionKey = new byte[0];

            string metadata = JsonConvert.SerializeObject(message.Metadata);

            byte[] uncompressedMetadata = System.Text.Encoding.UTF8.GetBytes(metadata);
            byte[] compressedMetadata   = GZIPCompressByteArray(uncompressedMetadata);

            byte[] uncompressedMessage = System.Text.Encoding.UTF8.GetBytes(message.Text);
            if (message.Encryption == MessageEncryption.RSA4096AES256)
            {
                byte[] aesKey = GetRandomData(256);

                encryptionKey = RSAEncryptByteArray(aesKey, publicKey);
                byte[] encryptedMessage = AESEncryptByteArray(uncompressedMessage, aesKey);

                uncompressedMessage = encryptedMessage;
            }
            byte[] compressedMessage = GZIPCompressByteArray(uncompressedMessage);

            byte[] header              = System.Text.Encoding.UTF8.GetBytes("TWS");
            byte   version             = (byte)message.Version;
            byte   compression         = (byte)message.Compression;
            byte   checksumType        = (byte)message.ChecksumType;
            byte   encryptionType      = (byte)message.Encryption;
            ushort encryptionKeyLength = (ushort)encryptionKey.Length;
            ushort metadataLength      = (ushort)compressedMetadata.Length;
            ushort messageLength       = (ushort)compressedMessage.Length;

            List <byte> pushDataList = new List <byte>();

            pushDataList.AddRange(header);
            pushDataList.Add(version);
            pushDataList.Add(compression);
            pushDataList.Add(checksumType);
            pushDataList.Add(encryptionType);
            pushDataList.AddRange(BitConverter.GetBytes(encryptionKeyLength));
            pushDataList.AddRange(BitConverter.GetBytes(metadataLength));
            pushDataList.AddRange(BitConverter.GetBytes(messageLength));
            pushDataList.AddRange(encryptionKey);
            pushDataList.AddRange(compressedMetadata);
            pushDataList.AddRange(compressedMessage);

            if (pushDataList.Count > 16 * 1024)
            {
                throw new Exception("Push data can't be bigger than 16 kbytes.");
            }

            return(pushDataList.ToArray());
        }
        public WantedSystemMessage GetWantedSystemMessage(Script scriptPubKey, RsaPrivateKey privateKey = null)
        {
            var msg = new WantedSystemMessage();

            if (scriptPubKey.Length < 13)
            {
                throw new Exception("This ScriptPubKey is not a valid Wanted System message.");
            }

            Op[] scriptPubKeyOps = scriptPubKey.ToOps().ToArray();
            if ((scriptPubKeyOps[0].Code != OpcodeType.OP_NOP) || (scriptPubKeyOps[1].Code != OpcodeType.OP_NOP) || (scriptPubKeyOps[2].Code != OpcodeType.OP_RETURN))
            {
                throw new Exception("This ScriptPubKey is not a valid Wanted System message.");
            }

            byte[] pd = scriptPubKeyOps[3].PushData;

            byte[] header = pd.Take <byte>(3).ToArray();
            msg.Version = pd[3];
            if (msg.Version != 1)
            {
                throw new Exception($"Wanted System message vesion {msg.Version} is not supported.");
            }

            msg.Compression = (MessageCompression)pd[4];
            if (msg.Compression != MessageCompression.GZip)
            {
                throw new Exception($"Wanted System message compression {msg.Compression} is not supported.");
            }

            msg.ChecksumType = (MessageChecksum)pd[5];
            if (msg.ChecksumType != MessageChecksum.None)
            {
                throw new Exception($"Wanted System message checksum {msg.ChecksumType} is not supported.");
            }

            msg.Encryption = (MessageEncryption)pd[6];
            if (msg.Encryption != MessageEncryption.RSA4096AES256)
            {
                throw new Exception($"Wanted System message encryption {msg.Encryption} is not supported.");
            }

            ushort encryptionKeyLength = BitConverter.ToUInt16(pd, 7);
            ushort metadataLength      = BitConverter.ToUInt16(pd, 9);
            ushort messageLength       = BitConverter.ToUInt16(pd, 11);

            byte[] encryptionKey      = new byte[encryptionKeyLength];
            byte[] compressedMetadata = new byte[metadataLength];
            byte[] compressedMessage  = new byte[messageLength];

            Array.Copy(pd, 13, encryptionKey, 0, encryptionKeyLength);
            Array.Copy(pd, 13 + encryptionKeyLength, compressedMetadata, 0, metadataLength);
            Array.Copy(pd, 13 + encryptionKeyLength + metadataLength, compressedMessage, 0, messageLength);

            byte[] uncompressedMetadata = GZIPDecompressByteArray(compressedMetadata);
            byte[] uncompressedMessage  = GZIPDecompressByteArray(compressedMessage);

            // process metadata using json serializer
            string metadata = System.Text.Encoding.UTF8.GetString(uncompressedMetadata);

            msg.Metadata = JsonConvert.DeserializeObject <WantedSystemMessageMetadata>(metadata);

            // Decrypt the message if needed
            if (msg.Encryption == MessageEncryption.RSA4096AES256)
            {
                if (privateKey == null)
                {
                    throw new Exception("The message is encrypted but the decryption key was not provided.");
                }

                byte[] aesKey = null;
                try
                {
                    aesKey = RSADecryptByteArray(encryptionKey, privateKey);
                }
                catch
                {
                    throw new Exception("The private key you provided isn't a match for the public key the message was encrypted with.");
                }

                uncompressedMessage = AESDecryptByteArray(uncompressedMessage, aesKey);
            }
            msg.Text = System.Text.Encoding.UTF8.GetString(uncompressedMessage);

            return(msg);
        }