
// readMessages provides functions to read Seekia chat messages
// The chat message structure will eventually be documented in /documentation/Specification.md

package readMessages

//TODO: Add an upper limit on bytes, and an upper limit for size of communication.
//TODO: Verify all message values and function inputs.

import "seekia/internal/cryptography/blake3"
import "seekia/internal/cryptography/chaPolyShrink"
import "seekia/internal/cryptography/edwardsKeys"
import "seekia/internal/cryptography/csidh"
import "seekia/internal/cryptography/mlkem"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"

import messagepack "github.com/vmihailenco/msgpack/v5"

import "bytes"
import "errors"
import "slices"

func VerifyMessageHashHex(inputHash string)bool{

	isValid := helpers.VerifyHexString(26, inputHash)

	return isValid
}

func VerifyMessageCipherKeyHex(inputCipherKey string)bool{

	isValid := helpers.VerifyHexString(32, inputCipherKey)

	return isValid
}

func ReadMessageHashHex(inputMessageHash string)([26]byte, error){

	messageHashBytes, err := encoding.DecodeHexStringToBytes(inputMessageHash)
	if (err != nil){
		return [26]byte{}, errors.New("ReadMessageHashHex called with invalid MessageHash: Not Hex: " + inputMessageHash)
	}

	if (len(messageHashBytes) != 26){
		return [26]byte{}, errors.New("ReadMessageHashHex called with invalid MessageHash: Invalid length: " + inputMessageHash)
	}

	messageHashArray := [26]byte(messageHashBytes)

	return messageHashArray, nil
}

func ReadMessageCipherKeyHex(inputCipherKey string)([32]byte, error){

	cipherKeyBytes, err := encoding.DecodeHexStringToBytes(inputCipherKey)
	if (err != nil){
		return [32]byte{}, errors.New("ReadMessageCipherKeyHex called with invalid inputCipherKey: Not Hex: " + inputCipherKey)
	}

	if (len(cipherKeyBytes) != 32){
		return [32]byte{}, errors.New("ReadMessageCipherKeyHex called with invalid inputCipherKey: Invalid length: " + inputCipherKey)
	}

	cipherKeyArray := [32]byte(cipherKeyBytes)

	return cipherKeyArray, nil
}

func VerifyMessageCipherKeyHashHex(inputCipherKeyHash string)bool{

	isValid := helpers.VerifyHexString(25, inputCipherKeyHash)

	return isValid
}

func ConvertMessageCipherKeyToCipherKeyHash(inputMessageCipherKey [32]byte)([25]byte, error){

	cipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, inputMessageCipherKey[:])
	if (err != nil) { return [25]byte{}, err }

	cipherKeyHashArray := [25]byte(cipherKeyHash)

	return cipherKeyHashArray, nil
}


// This function reads a chat message's public data
// It also computes and returns the message hash
// It does not decrypt the message.
// Outputs:
//	-bool: Able to read
//	-[26]byte: Message Hash
//	-int: Message version
//	-byte: Network type (1 == Mainnet, 2 == Testnet)
//	-[10]byte: Message Inbox
//	-messagepack.RawMessage: Message noncipheredSection bytes (needed to decrypt the cipheredMessage)
//	-[24]byte: DoubleSealedKeysNonce
//	-[]byte: DoubleSealedKeys
//	-[25]byte: CipherKeyHash
//	-[24]byte: CipheredMessageNonce
//	-[]byte: CipheredMessage
//	-error (will return err if there is a bug)
func ReadChatMessagePublicDataAndHash(verifyData bool, inputMessage []byte)(bool, [26]byte, int, byte, [10]byte, messagepack.RawMessage, [24]byte, []byte, [25]byte, [24]byte, []byte, error){

	ableToRead, messageVersion, messageNetworkType, messageInbox, messageNoncipheredSectionBytes, messageDoubleSealedKeysNonce, messageDoubleSealedKeys, messageCipherKeyHash, messageCipheredMessageNonce, messageCipheredMessage, err := ReadChatMessagePublicData(verifyData, inputMessage)
	if (err != nil) { return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, err }
	if (ableToRead == false){
		return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	messageHashSlice, err := blake3.GetBlake3HashAsBytes(26, inputMessage)
	if (err != nil) { return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, err }

	messageHash := [26]byte(messageHashSlice)

	return true, messageHash, messageVersion, messageNetworkType, messageInbox, messageNoncipheredSectionBytes, messageDoubleSealedKeysNonce, messageDoubleSealedKeys, messageCipherKeyHash, messageCipheredMessageNonce, messageCipheredMessage, nil
}

// This function reads a chat message's public data, and optionally verifies the message's public data.
// It does not compute the message hash, thus it is faster
// It does not decrypt the message.
// Outputs:
//	-bool: Able to read
//	-int: Message version
//	-byte: Network type (1 == Mainnet, 2 == Testnet)
//	-[10]byte: Message Inbox
//	-messagepack.RawMessage: Message noncipheredSection bytes (needed to decrypt the cipheredMessage)
//	-[24]byte: DoubleSealedKeysNonce
//	-[]byte: DoubleSealedKeys
//	-[25]byte: CipherKeyHash
//	-[24]byte: CipheredMessageNonce
//	-[]byte: CipheredMessage
//	-error (will return err if there is a bug)
func ReadChatMessagePublicData(verifyData bool, inputMessage []byte)(bool, int, byte, [10]byte, messagepack.RawMessage, [24]byte, []byte, [25]byte, [24]byte, []byte, error){

	var messageSlice []messagepack.RawMessage

	err := encoding.DecodeMessagePackBytes(false, inputMessage, &messageSlice)
	if (err != nil){
		// Cannot read message: Invalid messagepack
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	if (len(messageSlice) != 2){
		// Cannot read message: Invalid messagepack
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	messageNoncipheredSectionEncoded := messageSlice[0]
	cipheredMessageEncoded := messageSlice[1]

	var noncipheredSectionSlice []messagepack.RawMessage

	err = encoding.DecodeMessagePackBytes(false, messageNoncipheredSectionEncoded, &noncipheredSectionSlice)
	if (err != nil){
		// Malformed message: Invalid message content
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	if (len(noncipheredSectionSlice) != 7){
		// Malformed message: Invalid message noncipheredSection
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	messageVersionEncoded := noncipheredSectionSlice[0]
	networkTypeEncoded := noncipheredSectionSlice[1]
	recipientInboxEncoded := noncipheredSectionSlice[2]
	doubleSealedKeysNonceEncoded := noncipheredSectionSlice[3]
	doubleSealedKeysEncoded := noncipheredSectionSlice[4]
	cipherKeyHashEncoded := noncipheredSectionSlice[5]
	cipheredMessageNonceEncoded := noncipheredSectionSlice[6]

	messageVersion, err := encoding.DecodeRawMessagePackToInt(messageVersionEncoded)
	if (err != nil){
		// Malformed message: Invalid message version
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	if (messageVersion != 1){
		// We cannot read the message. It is created for a newer version of Seekia
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	messageNetworkType, err := encoding.DecodeRawMessagePackToByte(networkTypeEncoded)
	if (err != nil){
		// Malformed message: Invalid networkType
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	isValid := helpers.VerifyNetworkType(messageNetworkType)
	if (isValid == false){
		// Malformed message: Invalid networkType
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	recipientInbox, err := encoding.DecodeRawMessagePackTo10ByteArray(recipientInboxEncoded)
	if (err != nil){
		// Malformed message: Invalid recipient inbox
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	doubleSealedKeysNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(doubleSealedKeysNonceEncoded)
	if (err != nil){
		// Malformed message: Invalid doubleSealedKeysNonce
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	doubleSealedKeys, err := encoding.DecodeRawMessagePackToBytes(doubleSealedKeysEncoded)
	if (err != nil){
		// Malformed message: Invalid doubleSealedKeys
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	cipherKeyHash, err := encoding.DecodeRawMessagePackTo25ByteArray(cipherKeyHashEncoded)
	if (err != nil){
		// Malformed message: Invalid cipherKeyHash
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	cipheredMessageNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(cipheredMessageNonceEncoded)
	if (err != nil){
		// Malformed message: Invalid cipheredMessageNonce
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	cipheredMessage, err := encoding.DecodeRawMessagePackToBytes(cipheredMessageEncoded)
	if (err != nil){
		// Malformed message: Invalid cipheredMessage
		return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
	}

	if (verifyData == true){

		if (len(doubleSealedKeys) != 1748){
			// Invalid doubleSealedKeys: Invalid length
			return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
		}

		if (len(cipheredMessage) < 3){
			// Invalid Message: Invalid cipheredMessage
			return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
		}
	}

	return true, messageVersion, messageNetworkType, recipientInbox, messageNoncipheredSectionEncoded, doubleSealedKeysNonce, doubleSealedKeys, cipherKeyHash, cipheredMessageNonce, cipheredMessage, nil
}

// This struct defines a chat key set which is used to decrypt a chat message
// Each user may have multiple key sets, if they have shared newer keys more recently.
// They keep their old keys so they can decrypt messages sent to their older keys.
type ChatKeySet struct{

	NaclPublicKey [32]byte
	NaclPrivateKey [32]byte
	MlkemPrivateKey [64]byte
	CsidhPrivateKey [37]byte
}

// This function will decrypt a chat message with a recipient device chat keys list
// This is used by users who are decrypting messages sent to them
//Inputs:
//	-[]byte: InputMessage
//	-[32]byte: Double Sealed Keys decryption key
//	-[]ChatKeySet: RecipientChatDecryptionKeysList (contains decryption keys for each recipient chat key set)
//Outputs:
//	-bool: Able to read message (could be false if message is malformed or unable to decrypt)
//	-[26]byte: Message Hash
//	-int: Message Version
//	-byte: Message network type (1 == Mainnet, 2 == Testnet1)
//	-[32]byte: Message Cipher Key
//	-[16]byte: Sender Identity Hash
//	-[16]byte: Recipient Identity Hash
//	-int64: Message creation time (unix)
//	-string: Communication
//	-[22]byte: Sender Current secret inbox seed
//	-[22]byte: Sender Next secret inbox seed
//	-[11]byte: Sender Device Identifier
//	-int64: Sender Latest chat keys update time
//	-error (will return err if non-message inputs are malformed, or there is a bug)
func ReadChatMessage(inputMessage []byte, doubleSealedKeysDecryptionKey [32]byte, recipientDecryptionKeySetsList []ChatKeySet)(bool, [26]byte, int, byte, [32]byte, [16]byte, [16]byte, int64, string, [22]byte, [22]byte, [11]byte, int64, error){

	ableToRead, messageHash, messageVersion, messageNetworkType, _, messageNoncipheredSectionBytes, doubleSealedKeysNonce, doubleSealedKeys, expectedCipherKeyHash, cipheredMessageNonce, cipheredMessage, err := ReadChatMessagePublicDataAndHash(true, inputMessage)
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
	if (ableToRead == false){
		// Invalid message format
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(doubleSealedKeys, doubleSealedKeysDecryptionKey, doubleSealedKeysNonce, false, [32]byte{})
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
	if (ableToDecrypt == false){
		// doubleSealedKeys cannot be decrypted
		// Sender must be malicious
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	if (len(decryptedBytes) != 1712){
		// Sender must be malicious.
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	naclEncryptedKeyPiece1 := [80]byte(decryptedBytes[:80])
	mlkemEncryptedKeyPiece2 := [1568]byte(decryptedBytes[80:1648])
	senderCsidhPublicKey := [64]byte(decryptedBytes[1648:])

	isValid := csidh.VerifyCsidhPublicKey(senderCsidhPublicKey)
	if (isValid == false){
		// Sender must be malicious.
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	//Outputs:
	//	-bool: Able to decrypt
	//	-[32]byte: Basaldata decryption key
	//	-error (will be error if inputs are invalid)
	getBasaldataDecryptionKey := func()(bool, [32]byte, error){

		// This cycles through all chat decryption keys the user has
		// They share new keys on their profile, and delete old keys after a certain time period

		for _, keySetObject := range recipientDecryptionKeySetsList{

			recipientNaclPublicKey := keySetObject.NaclPublicKey
			recipientNaclPrivateKey := keySetObject.NaclPrivateKey
			recipientMlkemPrivateKey := keySetObject.MlkemPrivateKey
			recipientCsidhPrivateKey := keySetObject.CsidhPrivateKey

			ableToDecrypt, keyPiece1, err := nacl.DecryptNaclEncryptedKey(naclEncryptedKeyPiece1, recipientNaclPublicKey, recipientNaclPrivateKey)
			if (err != nil) { return false, [32]byte{}, err }
			if (ableToDecrypt == false){
				// Keys are not the correct decryption keys
				// Skip to next keys
				continue
			}

			ableToDecrypt, keyPiece2, err := mlkem.DecryptMlkemEncryptedKey(mlkemEncryptedKeyPiece2, recipientMlkemPrivateKey)
			if (err != nil) { return false, [32]byte{}, err }
			if (ableToDecrypt == false){
				// This should never happen, unless someone is impersonating us by sharing our inbox and old keys
				// Each chat key set will have a set of 3 unique keys that all change together
				return false, [32]byte{}, nil
			}

			keyPiece3, err := csidh.CalculateCsidhSharedKey(senderCsidhPublicKey, recipientCsidhPrivateKey)
			if (err != nil) { return false, [32]byte{}, err }

			basaldataDerivationHashInput := slices.Concat(keyPiece1[:], keyPiece2[:], keyPiece3[:])

			basaldataDecryptionKey, err := blake3.Get32ByteBlake3Hash(basaldataDerivationHashInput)
			if (err != nil) { return false, [32]byte{}, err }

			return true, basaldataDecryptionKey, nil
		}

		// We don't have the keys needed to decrypt the message.
		return false, [32]byte{}, nil
	}

	ableToDecrypt, basaldataDecryptionKey, err := getBasaldataDecryptionKey()
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
	if (ableToDecrypt == false){
		// We don't have the keys to decrypt, or message is invalid
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	// CipheredMessageKey is a hash of the Basaldata decryption key
	// This allows users to report messages and reveal only the cipheredMessage
	// This way, only the innerMessage contents are revealed, and the basaldata remains encrypted

	messageCipherKey, err := blake3.GetBlake3HashAsBytes(32, basaldataDecryptionKey[:]) 
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }

	messageCipherKeyArray := [32]byte(messageCipherKey)

	messageCipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, messageCipherKey)
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }

	areEqual := bytes.Equal(messageCipherKeyHash, expectedCipherKeyHash[:])
	if (areEqual == false){
		// Cipher key hash does not match expected cipher key hash
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	ableToRead, senderIdentityHash, senderIdentityType, encryptedBasaldata, basaldataNonce, messageCommunication, err := readCipheredMessage(1, cipheredMessage, messageCipherKeyArray, cipheredMessageNonce, messageNoncipheredSectionBytes)
	if (ableToRead == false){
		// Invalid ciphered message
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	// Now we decrypt basaldata

	ableToDecrypt, decryptedBasaldataBytes, err := chaPolyShrink.DecryptChaPolyShrink(encryptedBasaldata, basaldataDecryptionKey, basaldataNonce, false, [32]byte{})
	if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
	if (ableToDecrypt == false) {
		// Unable to decrypt. Sender is malicious.
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	var basaldataSlice []messagepack.RawMessage

	err = encoding.DecodeMessagePackBytes(false, decryptedBasaldataBytes, &basaldataSlice)
	if (err != nil) {
		// Message basaldata messagepack is invalid
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	if (len(basaldataSlice) != 6){
		// Message basaldata is invalid
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	recipientIdentityHashEncoded := basaldataSlice[0]
	messageCreationTimeUnixEncoded := basaldataSlice[1]
	senderCurrentSecretInboxSeedEncoded := basaldataSlice[2]
	senderNextSecretInboxSeedEncoded := basaldataSlice[3]
	senderDeviceIdentifierEncoded := basaldataSlice[4]
	senderLatestChatKeysUpdateTimeEncoded := basaldataSlice[5]

	recipientIdentityHash, err := encoding.DecodeRawMessagePackTo16ByteArray(recipientIdentityHashEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid RecipientIdentityHash
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	messageCreationTimeUnix, err := encoding.DecodeRawMessagePackToInt64(messageCreationTimeUnixEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid CreationTime
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	senderCurrentSecretInboxSeed, err := encoding.DecodeRawMessagePackTo22ByteArray(senderCurrentSecretInboxSeedEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid SenderCurrentSecretInboxSeed
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	senderNextSecretInboxSeed, err := encoding.DecodeRawMessagePackTo22ByteArray(senderNextSecretInboxSeedEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid SenderNextSecretInboxSeed
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	senderDeviceIdentifier, err := encoding.DecodeRawMessagePackTo11ByteArray(senderDeviceIdentifierEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid SenderDeviceIdentifier
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	senderLatestChatKeysUpdateTime, err := encoding.DecodeRawMessagePackToInt64(senderLatestChatKeysUpdateTimeEncoded)
	if (err != nil) {
		// Malformed message basaldata: Invalid SenderLatestChatKeysUpdateTime
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	recipientIdentityType, err := identity.GetIdentityTypeFromIdentityHash(recipientIdentityHash)
	if (err != nil) {
		// Malformed message basaldata: Invalid RecipientIdentityHash
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	if (senderIdentityType != recipientIdentityType){
		// Malformed message basaldata: Recipient and sender identity types do not match.
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	isValid = helpers.VerifyCreationTime(messageCreationTimeUnix)
	if (isValid == false){
		// Malformed message basaldata: Contains invalid messageCreationTime
		return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
	}

	return true, messageHash, messageVersion, messageNetworkType, messageCipherKeyArray, senderIdentityHash, recipientIdentityHash, messageCreationTimeUnix, messageCommunication, senderCurrentSecretInboxSeed, senderNextSecretInboxSeed, senderDeviceIdentifier, senderLatestChatKeysUpdateTime, nil	
}

// This is used by moderators to decrypt a chat message
// This does not decrypt the basaldata
//Outputs:
//	-bool: Able to read message (could be false if message is malformed or unable to decrypt)
//	-[26]byte: Message Hash
//	-int: Message Version
//	-byte: Message network type (1 == Mainnet, 2 == Testnet1)
//	-[16]byte: Sender Identity Hash
//	-string: Communication
//	-error (will return err if non-message inputs are malformed, or there is a bug)
func ReadChatMessageWithCipherKey(inputMessage []byte, messageCipherKey [32]byte)(bool, [26]byte, int, byte, [16]byte, string, error){

	ableToRead, messageHash, messageVersion, messageNetworkType, _, messageNoncipheredSectionBytes, _, _, expectedCipherKeyHash, cipheredMessageNonce, cipheredMessage, err := ReadChatMessagePublicDataAndHash(true, inputMessage)
	if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }
	if (ableToRead == false){
		// Invalid message format
		return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
	}

	cipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, messageCipherKey[:])
	if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }

	areEqual := bytes.Equal(cipherKeyHash, expectedCipherKeyHash[:])
	if (areEqual == false){
		// Invalid message: Cipher key hash does not match
		return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
	}

	ableToRead, senderIdentityHash, _, _, _, messageCommunication, err := readCipheredMessage(messageVersion, cipheredMessage, messageCipherKey, cipheredMessageNonce, messageNoncipheredSectionBytes)
	if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }
	if (ableToRead == false){
		return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
	}

	return true, messageHash, messageVersion, messageNetworkType, senderIdentityHash, messageCommunication, nil
}

//Outputs:
//	-bool: Able to read (message is decryptable and well formed)
//	-[16]byte: Sender Identity Hash
//	-string: Sender Identity Type
//	-[]byte: Encrypted Basaldata
//	-[24]byte: Basaldata nonce
//	-string: Communication
//	-error (this will return err if there is a bug in the function)
func readCipheredMessage(messageVersion int, cipheredMessage []byte, cipheredMessageKey [32]byte, cipheredMessageNonce [24]byte, noncipheredSectionBytes messagepack.RawMessage)(bool, [16]byte, string, []byte, [24]byte, string, error){

	if (messageVersion != 1){
		return false, [16]byte{}, "", nil, [24]byte{}, "", errors.New("readCipheredMessage called with invalid messageVersion")
	}

	noncipheredSectionHash, err := blake3.Get32ByteBlake3Hash(noncipheredSectionBytes)
	if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }

	ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredMessage, cipheredMessageKey, cipheredMessageNonce, true, noncipheredSectionHash)
	if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }
	if (ableToDecrypt == false) {
		// Unable to decrypt. Sender is malicious.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	// Now we read inner message

	var innerMessageSlice []messagepack.RawMessage

	err = encoding.DecodeMessagePackBytes(false, decryptedBytes, &innerMessageSlice)
	if (err != nil) {
		// Inner message messagepack is invalid
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	if (len(innerMessageSlice) != 2){
		// Inner message messagepack is invalid
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	innerMessageSignatureEncoded := innerMessageSlice[0]
	innerMessageRawMessagepack := innerMessageSlice[1]

	innerMessageSignature, err := encoding.DecodeRawMessagePackTo64ByteArray(innerMessageSignatureEncoded)
	if (err != nil){
		// Malformed inner message: Invalid innerMessageSignature
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	var innerMessageContentSlice []messagepack.RawMessage

	err = encoding.DecodeMessagePackBytes(false, innerMessageRawMessagepack, &innerMessageContentSlice)
	if (err != nil) {
		// Message Inner plaintext messagepack is invalid
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	if (len(innerMessageContentSlice) != 5){
		// Malformed inner message: Invalid inner message content
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	senderIdentityKeyEncoded := innerMessageContentSlice[0]
	senderIdentityTypeEncoded := innerMessageContentSlice[1]
	basaldataNonceEncoded := innerMessageContentSlice[2]
	encryptedBasaldataEncoded := innerMessageContentSlice[3]
	communicationEncoded := innerMessageContentSlice[4]

	senderIdentityKey, err := encoding.DecodeRawMessagePackTo32ByteArray(senderIdentityKeyEncoded)
	if (err != nil){
		// Malformed inner message: Sender identity key is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	senderIdentityType, err := encoding.DecodeRawMessagePackToString(senderIdentityTypeEncoded)
	if (err != nil){
		// Malformed inner message: Sender identity type is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	basaldataNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(basaldataNonceEncoded)
	if (err != nil){
		// Malformed inner message: Basaldata nonce is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	encryptedBasaldata, err := encoding.DecodeRawMessagePackToBytes(encryptedBasaldataEncoded)
	if (err != nil){
		// Malformed inner message: Encrypted basaldata is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	messageCommunication, err := encoding.DecodeRawMessagePackToString(communicationEncoded)
	if (err != nil){
		// Malformed inner message: Message communication is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	//TODO: Verify communication is valid

	if (senderIdentityType != "Mate" && senderIdentityType != "Moderator"){
		// Malformed inner message: Invalid senderIdentityType.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	innerContentHash, err := blake3.Get32ByteBlake3Hash(innerMessageRawMessagepack)
	if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }

	isValid := edwardsKeys.VerifySignature(senderIdentityKey, innerMessageSignature, innerContentHash)
	if (isValid == false) {
		// Malformed inner message: signature is invalid.
		return false, [16]byte{}, "", nil, [24]byte{}, "", nil
	}

	senderIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(senderIdentityKey, senderIdentityType)
	if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }

	return true, senderIdentityHash, senderIdentityType, encryptedBasaldata, basaldataNonce, messageCommunication, nil
}



