// Arup Guha
// 9/13/2022
// Example to encrypt using Hill cipher.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int* hillmult(int** m, int* plain, int n);
int* convert(char* str, int sI, int n);
char* convertBack(int* cipher, int n);

int main(void) {

    // Read in the matrix size.
    int n;
    scanf("%d", &n);

    // Allocates memory for the matrix.
    int** mat = malloc(n*sizeof(int*));
    for (int i=0; i<n; i++)
        mat[i] = malloc(n*sizeof(int));

    // Read in the matrix.
    for (int i=0; i<n; i++)
        for (int j=0; j<n; j++)
            scanf("%d", &mat[i][j]);

    // Assumes input is no bigger than 100 chars.
    // Assume input string length is multiple of n.
    char plain[101];
    scanf("%s", plain);

    // So I don't call strlen a lot...
    int len = strlen(plain);

    // i is the starting index of each block.
    for (int i=0; i<len; i+=n) {

        // Convert to numbers.
        int* plainNum = convert(plain, i, n);

        // Now, encrypt it!!!
        int* cipher = hillmult(mat, plainNum, n);

        // Convert back to letters.
        char* printCipher = convertBack(cipher, n);

        // Print out to screen.
        printf("%s", printCipher);

        // I don't need this any more.
        free(cipher);
        free(printCipher);
    }

    // Go to next line.
    printf("\n");

    // Free dynamically allocated memory.
    for (int i=0; i<n; i++) free(mat[i]);
    free(mat);

    return 0;
}

// Pre-condition: Assumes m is an n by n key for the Hill
// Cipher that is valid (under mod 26) and that plain is an
// array of size n storing integers in the range [0, 25]
// representing letters.
// Post-condition: returns the encryption of plain as an array
// of size n.
int* hillmult(int** m, int* plain, int n) {

    int* res = malloc(n*sizeof(int));

    // i is the row of the matrix m we are multiplying by.
    for (int i=0; i<n; i++) {

        // Set this to 0 since malloc doesn't.
        res[i] = 0;

        // This calculates the "dot product" for this one letter.
        for (int j=0; j<n; j++)
            res[i] = (res[i] + m[i][j]*plain[j])%26;
    }

    return res;
}

// Converts n characters starting at index sI to 0..25 int values.
// Assumes all characters are uppercase letters.
int* convert(char* str, int sI, int n) {

    // Store result here.
    int* res = malloc(sizeof(int)*n);

    // Loop through the desired block of characters copying in the int values.
    for (int i=sI; i<sI+n; i++)
        res[i-sI] = str[i] - 'A';
    return res;
}

// Pre-condition: cipher is an array of n integer in the range 0..25
// representing letters.
// Post-condition: the letters are stored and returned in a null
// terminated string.
char* convertBack(int* cipher, int n) {

    // Store result here.
    char* res = malloc(sizeof(char)*(n+1));

    // Convert numbers to Ascii values.
    for (int i=0; i<n; i++)
        res[i] = (char)(cipher[i]+'A');

    // Important...then return.
    res[n] = '\0';
    return res;
}
