using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lab2
{
    public class Program
    {
        private const byte T_PLUS = 165;
        private const byte G_PLUS = 23;
        private const byte T_SHIFT = 3;
        private const byte G_SHIFT = 3;
        private const int TARGET_LENGTH = 128;

        static void Main(string[] args)
        {

            string data = "very-long-test-password";

            if (string.IsNullOrEmpty(data))
            {
                Console.WriteLine("Строка не может быть пустой.");
                return;
            }

            Console.WriteLine($"Исходная строка: {data}");

            data += data.Length;

            data = MultiplyString(data);

            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);


            var strBytes = Encoding.GetEncoding("windows-1251").GetBytes(data);

           

            var hash = Hash(strBytes);

            int result = 0;
            for (int i = 0; i < 24; i++) result += hash[i];

            Console.WriteLine($"Хеш: {result}");

            Console.ReadKey();
        }

        private static string MultiplyString(string s)
        {
            while (s.Length < TARGET_LENGTH)
            {
                s += s; // Удваиваем строку
            }

            return s[..TARGET_LENGTH]; // Обрезаем до TargetLength символов
        }
        public static byte[] Hash(byte[] msgBytes)
        {
            int hashLength = msgBytes.Length;

            if (msgBytes == null)
            {
                throw new ArgumentNullException(nameof(msgBytes));
            }

            var hash = new byte[hashLength];
            var TArray = new byte[hashLength, msgBytes.Length, 2];
            var GArray = new byte[hashLength];


            for (int i = 0; i < hash.Length; i++)
            {
                G(i, GArray);
            }

            for (int i = 0; i < TArray.GetLength(0); i++)
            {
                for (int j = 0; j < TArray.GetLength(1); j++)
                {
                    T(i, j, msgBytes, TArray, GArray);
                }

                hash[i] = TArray[i, TArray.GetLength(1) - 1, 1];
            }

            return hash;
        }
        private static void G(int index, byte[] GArray)
        {
            if (index == 0)
                GArray[index] = CircularShiftLeft((byte)(G_PLUS + 1), G_SHIFT);
            else
                GArray[index] = CircularShiftLeft((byte)(G_PLUS + GArray[index - 1]), G_SHIFT);
        }
        private static void T(int row, int col, byte[] msgBytes, byte[,,] TArray, byte[] GArray)
        {

            byte res1;
            byte res2;

            if (row == 0) 
            {
                if (col == 0)
                {
                    res1 = (byte)(GArray[row] ^ CircularShiftLeft(msgBytes[0], T_SHIFT));
                    res2 = (byte)(T_PLUS ^ 1);
                }
                else
                {
                    res1 = (byte)(TArray[row, col - 1, 1] ^ CircularShiftLeft(msgBytes[col], T_SHIFT));
                    res2 = (byte)(T_PLUS ^ msgBytes[col - 1]);
                }
            }
            else
            {
                if (col == 0)
                {
                    res1 = (byte)(GArray[row] ^ CircularShiftLeft(TArray[row - 1, col, 0], T_SHIFT));
                    res2 = (byte)(T_PLUS ^ GArray[row - 1]);
                }
                else
                {
                    res1 = (byte)(TArray[row, col - 1, 1] ^ CircularShiftLeft(TArray[row - 1, col, 0], T_SHIFT));
                    res2 = (byte)(T_PLUS ^ TArray[row - 1, col - 1, 0]);
                }
            }

            TArray[row, col, 0] = res1;
            TArray[row, col, 1] = (byte)(res1 + res2);
        }
        private static byte CircularShiftLeft(byte value, byte count)
        {
            return (byte)((value << count) | (value >> (8 - count)));
        }


    }
}
