internal Deserializer(CryptoDtoChannel channel, ReadOnlySpan <byte> bytes, bool ignoreSequence)
            {
                sequenceValid = false;
                headerLength  = Unsafe.ReadUnaligned <ushort>(ref MemoryMarshal.GetReference(bytes));                               //.NET Standard 2.0 doesn't have BitConverter.ToUInt16(Span<T>)
                if (bytes.Length < (2 + headerLength))
                {
                    throw new CryptographicException("Not enough bytes to process packet.");
                }

                ReadOnlySpan <byte> headerBuffer = bytes.Slice(2, headerLength);

                header = MessagePackSerializer.Deserialize <CryptoDtoHeaderDto>(headerBuffer.ToArray());

                if (header.ChannelTag != channel.ChannelTag)
                {
                    throw new CryptographicException("Channel Tag doesn't match provided Channel");
                }

                switch (header.Mode)
                {
                case CryptoDtoMode.ChaCha20Poly1305:
                {
                    int aeLength = bytes.Length - (2 + headerLength);
                    ReadOnlySpan <byte> aePayloadBuffer = bytes.Slice(2 + headerLength, aeLength);

                    ReadOnlySpan <byte> adBuffer = bytes.Slice(0, 2 + headerLength);

                    Span <byte> nonceBuffer = stackalloc byte[Aead.NonceSize];
                    BinaryPrimitives.WriteUInt64LittleEndian(nonceBuffer.Slice(4), header.Sequence);

                    ReadOnlySpan <byte> receiveKey = channel.GetReceiveKey(header.Mode);
                    var aead = new ChaCha20Poly1305(receiveKey.ToArray());
                    ReadOnlySpan <byte> decryptedPayload = aead.Decrypt(aePayloadBuffer.ToArray(), adBuffer.ToArray(), nonceBuffer);

                    if (ignoreSequence)
                    {
                        sequenceValid = channel.IsReceivedSequenceAllowed(header.Sequence);
                    }
                    else
                    {
                        channel.CheckReceivedSequence(header.Sequence);             //The packet has passed MAC, so now check if it's being duplicated or replayed
                        sequenceValid = true;
                    }

                    dtoNameLength = Unsafe.ReadUnaligned <ushort>(ref MemoryMarshal.GetReference(decryptedPayload));           //.NET Standard 2.0 doesn't have BitConverter.ToUInt16(Span<T>)

                    if (decryptedPayload.Length < (2 + dtoNameLength))
                    {
                        throw new CryptographicException("Not enough bytes to process packet. (2) " + dtoNameLength + " " + decryptedPayload.Length);
                    }

                    dtoNameBuffer = decryptedPayload.Slice(2, dtoNameLength);

                    dataLength = Unsafe.ReadUnaligned <ushort>(ref MemoryMarshal.GetReference(decryptedPayload.Slice(2 + dtoNameLength, 2)));           //.NET Standard 2.0 doesn't have BitConverter.ToUInt16(Span<T>)

                    if (decryptedPayload.Length < (2 + dtoNameLength + 2 + dataLength))
                    {
                        throw new CryptographicException("Not enough bytes to process packet. (3) " + dataLength + " " + decryptedPayload.Length);
                    }
                    dataBuffer = decryptedPayload.Slice(2 + dtoNameLength + 2, dataLength);
                    break;
                }

                default:
                    throw new CryptographicException("Mode not recognised");
                }
            }