import java.util.*;

public class SDES {

    static int[] PermutationP10 = {3, 5, 2, 7, 4, 10, 1, 9, 8, 6};
    static int[] PermutationP8 = {6, 3, 7, 4, 8, 5, 10, 9};
    static int[] Initial_Permutation_IP = {2, 6, 3, 1, 4, 8, 5, 7};
    static int[] Expanded_Permutation_EP = {4, 1, 2, 3, 2, 3, 4, 1};
    static int[] PermutationP4 = {2, 4, 3, 1};
    static int[] Inverse_of_Initial_Permutation_IP_inv = {4, 1, 3, 5, 7, 2, 8, 6};
    static int[][] S_Box_0 = {
            {1, 0, 3, 2}, 
            {3, 2, 1, 0}, 
            {0, 2, 1, 3}, 
            {3, 1, 3, 2}
    };
    static int[][] S_Box_1 = {
            {0, 1, 2, 3}, 
            {2, 0, 1, 3}, 
            {3, 0, 1, 0}, 
            {2, 1, 0, 3}
    };

    static int[] key1_8bits = new int[8];
    static int[] key2_8bits = new int[8];

    public static String binary__(int value) {
        switch (value) {
            case 0: return "00";
            case 1: return "01";
            case 2: return "10";
            default: return "11";
        }
    }

    public static int[] swap_bits(int[] arr, int sizes) {
        int[] left = new int[sizes];
        int[] right = new int[sizes];

        for (int i = 0; i < sizes; i++) {
            left[i] = arr[i];
            right[i] = arr[i + sizes];
        }

        int[] output = new int[2 * sizes];

        for (int i = 0; i < sizes; i++) {
            output[i] = right[i];
            output[i + sizes] = left[i];
        }

        return output;
    }

    public static int binaryToDecimal(int[] vec) {
        int base = 1, decimal_value = 0;
        for (int i = vec.length - 1; i >= 0; i--) {
            decimal_value += vec[i] * base;
            base *= 2;
        }

        return decimal_value;
    }

    public static int[] function_(int[] tmpp, int[] key__) {
        int[] left_4bits = new int[4];
        int[] right_4bits = new int[4];

        for (int i = 0; i < 4; i++) {
            left_4bits[i] = tmpp[i];
            right_4bits[i] = tmpp[i + 4];
        }

        int[] ep = new int[8];

        for (int i = 0; i < 8; i++) {
            ep[i] = right_4bits[Expanded_Permutation_EP[i] - 1];
        }

        for (int i = 0; i < 8; i++) {
            tmpp[i] = key__[i] ^ ep[i];
        }

        int[] left_4bits_1 = new int[4];
        int[] right_4bits_1 = new int[4];

        for (int i = 0; i < 4; i++) {
            left_4bits_1[i] = tmpp[i];
            right_4bits_1[i] = tmpp[i + 4];
        }

        int row, column, value;

        int[] vec = {left_4bits_1[0], left_4bits_1[3]};
        row = binaryToDecimal(vec);

        vec = new int[]{left_4bits_1[1], left_4bits_1[2]};
        column = binaryToDecimal(vec);

        value = S_Box_0[row][column];
        String str_left = binary__(value);

        vec = new int[]{right_4bits_1[0], right_4bits_1[3]};
        row = binaryToDecimal(vec);

        vec = new int[]{right_4bits_1[1], right_4bits_1[2]};
        column = binaryToDecimal(vec);

        value = S_Box_1[row][column];
        String str_right = binary__(value);

        int[] r_ = new int[4];
        for (int i = 0; i < 2; i++) {
            r_[i] = str_left.charAt(i) - '0';
            r_[i + 2] = str_right.charAt(i) - '0';
        }

        int[] r_p4 = new int[4];

        for (int i = 0; i < 4; i++) {
            r_p4[i] = r_[PermutationP4[i] - 1];
        }

        for (int i = 0; i < 4; i++) {
            left_4bits[i] = left_4bits[i] ^ r_p4[i];
        }

        int[] output_8bits = new int[8];

        for (int i = 0; i < 4; i++) {
            output_8bits[i] = left_4bits[i];
            output_8bits[i + 4] = right_4bits[i];
        }

        return output_8bits;
    }

    public static int[] decryptionOfCipherText(int[] cipherTextBinary) {
        int[] tmp = new int[8];

        for (int i = 0; i < 8; i++) {
            tmp[i] = cipherTextBinary[Initial_Permutation_IP[i] - 1];
        }

        int[] arr1 = function_(tmp, key2_8bits);

        int[] after_swap = swap_bits(arr1, arr1.length / 2);

        int[] arr2 = function_(after_swap, key1_8bits);

        int[] decrypted = new int[8];

        for (int i = 0; i < 8; i++) {
            decrypted[i] = arr2[Inverse_of_Initial_Permutation_IP_inv[i] - 1];
        }

        return decrypted;
    }

    public static int[] encryptionOfPlainText(int[] plainTextBinary) {
        int[] tmp = new int[8];

        for (int i = 0; i < plainTextBinary.length; i++) {
            tmp[i] = plainTextBinary[Initial_Permutation_IP[i] - 1];
        }

        int[] arr1 = function_(tmp, key1_8bits);

        int[] after_swap = swap_bits(arr1, arr1.length / 2);

        int[] arr2 = function_(after_swap, key2_8bits);

        int[] cipherText_8bits = new int[8];

        for (int i = 0; i < 8; i++) {
            cipherText_8bits[i] = arr2[Inverse_of_Initial_Permutation_IP_inv[i] - 1];
        }

        return cipherText_8bits;
    }

    public static int[] decimalToBinary(int decimal) {
        int[] binaryNum = new int[8];
        int i = 0;
        while (decimal > 0) {
            binaryNum[i] = decimal % 2;
            decimal = decimal / 2;
            i++;
        }
        return binaryNum;
    }

    public static void main(String[] args) {
        int[] plainText = {1, 0, 1, 1, 0, 1, 0, 0};
        int[] cipherText = encryptionOfPlainText(plainText);
        System.out.println("Encrypted Text: " + Arrays.toString(cipherText));

        int[] decryptedText = decryptionOfCipherText(cipherText);
        System.out.println("Decrypted Text: " + Arrays.toString(decryptedText));
    }
}

