# Kush Patel (2409544)

# Task 1:
# Create a Polybius cipher matrix
Polybius <- matrix(c(
  ' ', 'Z', 'M', 'D', ' ', 'K', 'W', 'Q', ' ', 'G',  # Row 0
  'V', ' ', 'A', ' ', 'R', ' ', 'E', ' ', 'T', 'O',  # Row 1
  ' ', 'J', 'I', 'S', 'B', 'P', 'Y', ' ', 'F', ' ',  # Row 2
  'L', ' ', ' ', 'C', ' ', 'U', 'H', 'N', ' ', 'X'   # Row 3
), nrow = 4, byrow = TRUE)  

# Assign row names (0 to 3) and column names (0 to 9) 
rownames(Polybius) <- 0:3
colnames(Polybius) <- 0:9

# Print the Polybius cipher matrix to verify
print("Polybius Matrix:")
print(Polybius)

# Task 2: Encrypt the Message "CAPTURETHEFORT"

# Step 1: Define the message to be encrypted
message <- "CAPTURETHEFORT"

# Step 2: Convert the message into individual characters
# `substring()` extracts each character from the message string as a separate element in a character vector
message_chars <- substring(message, 1:nchar(message), 1:nchar(message))

# Step 3: Initialize an empty vector to store the encrypted ciphertext
# `character(0)` creates an empty character vector to store the numeric codes
ciphertext <- character(0)

# Step 4: Loop through each character in the message to find its position in the Polybius matrix
for (char in message_chars) {
  # Find the row and column indices of the character in the Polybius matrix
  pos <- which(Polybius == char, arr.ind = TRUE)  # Returns a matrix with row and column indices
  
  if (length(pos) > 0) {  # If the character exists in the Polybius matrix
    # Extract row and column indices and adjust for 0-based indexing
    row_num <- pos[1] - 1  # Subtract 1 from the row index to make it 0-based
    col_num <- pos[2] - 1  # Subtract 1 from the column index to make it 0-based
    # Combine the row and column into a single string in "rowcolumn" format
    ciphertext <- c(ciphertext, sprintf("%d%d", row_num, col_num))
  }
}

# Print the encrypted message as a series of two-digit strings
print("Ciphertext:")
print(ciphertext)

# Task 3: Convert the Ciphertext into Groups of 5 Digits

# Step 1: Check if the ciphertext length is a multiple of 5
# Use the modulus operator (%%) to find the remainder when the length is divided by 5
remainder <- length(ciphertext) %% 5

if (remainder > 0) {
  # If the remainder is greater than 0, calculate the number of digits needed to pad the ciphertext
  padding_needed <- 5 - remainder
  # Generate random digits (0-9) to fill the padding
  # `sample()` generates the required number of random digits, allowing repeats
  padding <- sample(0:9, padding_needed, replace = TRUE)
  # Add the random digits to the ciphertext as strings
  ciphertext <- c(ciphertext, sprintf("%d", padding))
}

# Step 2: Format the ciphertext into groups of 5 digits
# Combine all the ciphertext elements into a single string
ciphertext_string <- paste(ciphertext, collapse = "")

# Split the ciphertext string into groups of 5 characters using `substring()`
# The start and end points of each group are specified using sequences
groups <- substring(ciphertext_string, seq(1, nchar(ciphertext_string), 5), seq(5, nchar(ciphertext_string) + 4, 5))

# Combine the groups of 5 into a single string separated by spaces
finaltext <- paste(groups, collapse = " ")

# Display the final formatted ciphertext
print("Final formatted ciphertext:")
print(finaltext)


#-----------------------------------------------------------------------------------------------

# Kush Patel (2409544)

# Task 1: Define the Polybius Cipher Matrix
Polybius <- matrix(c(
  ' ', 'Z', 'M', 'D', ' ', 'K', 'W', 'Q', ' ', 'G',  # Row 0
  'V', ' ', 'A', ' ', 'R', ' ', 'E', ' ', 'T', 'O',  # Row 1
  ' ', 'J', 'I', 'S', 'B', 'P', 'Y', ' ', 'F', ' ',  # Row 2
  'L', ' ', ' ', 'C', ' ', 'U', 'H', 'N', ' ', 'X'   # Row 3
), nrow = 4, byrow = TRUE)

# Assign row names (0 to 3) and column names (0 to 9) 
rownames(Polybius) <- 0:3
colnames(Polybius) <- 0:9

# Print the Polybius cipher matrix to verify
cat("Polybius Matrix:\n")
print(Polybius)
#--------------------------------------------------------------------------------------------------
#Task 2
#Task 2.1 Define the ciphertext
ciphertext <- c("24160", "63616", "14162", "61935", "14163", "71602", "26222", "33719", "18008")

# Combine all segments of the ciphertext into a single long string of digits.
combined_ciphertext <- paste(ciphertext, collapse = "")

# Initialize an empty string for the decrypted message.
decrypted_message <- ""

# Loop through the combined ciphertext, taking two digits at a time.
for (i in seq(1, nchar(combined_ciphertext), by = 2)) {
  # Extract the row and column from the current pair of digits.
  row <- as.integer(substr(combined_ciphertext, i, i))
  col <- as.integer(substr(combined_ciphertext, i + 1, i + 1))
  
  # Validate row and column indices and retrieve the character from the matrix.
  if (!is.na(row) && !is.na(col) && row >= 0 && row <= 3 && col >= 0 && col <= 9) {
    # Adjust for 1-based indexing and get the character.
    character <- Polybius[row + 1, col + 1]
    decrypted_message <- paste0(decrypted_message, character)
  } else {
    # Append a placeholder for invalid indices.
    decrypted_message <- paste0(decrypted_message, "!")
  }
}

# Display the decrypted message.
cat("Decrypted Message:\n")
cat(decrypted_message, "\n")



# Task 2.2: Encrypt a Message with the Keyword "APPLE"
message <- "RAISETHEFLAG"
keyword <- "APPLE"

# Function to get the row and column of a letter from the Polybius matrix.
get_position <- function(letter) {
  pos <- which(Polybius == letter, arr.ind = TRUE)
  if (length(pos) > 0) {
    return(c(pos[1] - 1, pos[2] - 1))  # Return 0-based row and column indices.
  }
  return(c(NA, NA))  # Return NA if the letter is not in the matrix.
}

# Split the message and keyword into individual characters.
message_chars <- unlist(strsplit(message, ""))
keyword_chars <- unlist(strsplit(keyword, ""))

# Repeat the keyword to match the length of the message.
extended_keyword <- rep(keyword_chars, length.out = length(message_chars))

# Generate positions for message and keyword characters.
message_positions <- t(sapply(message_chars, get_position))
keyword_positions <- t(sapply(extended_keyword, get_position))

# Encrypt the message by combining positions from the message and keyword.
encrypted_codes <- apply(cbind(message_positions, keyword_positions), 1, function(pos) {
  new_row <- (pos[1] + pos[3]) %% 4
  new_col <- (pos[2] + pos[4]) %% 10
  sprintf("%d%d", new_row, new_col)
})

# Combine the encrypted codes into a single string.
encrypted_message <- paste(encrypted_codes, collapse = "")

# Format the encrypted message into groups of 5 characters.
formatted_encrypted <- gsub("(.{5})", "\\1 ", encrypted_message)

# Display the encrypted message.
cat("\nEncrypted Message with Keyword 'APPLE':\n", formatted_encrypted, "\n")



#Task 2.3: Input ciphertext and the decryption keyword
ciphertext <- "48521 82559 53320 83151 44382 13349 40352 42260 48521 84349 48343 23518"
keyword <- "LEMON"

# Step 1: Convert the ciphertext into pairs
ciphertext_clean <- gsub(" ", "", ciphertext)  # Remove spaces
ciphertext_pairs <- strsplit(ciphertext_clean, "")[[1]]
ciphertext_pairs <- as.numeric(ciphertext_pairs)

# Step 2: Create a vector of numeric values for the keyword
keyword_numeric <- c()
for (char in strsplit(keyword, "")[[1]]) {
  match_position <- which(Polybius == char, arr.ind = TRUE)
  if (nrow(match_position) > 0) {
    # Calculate numeric value: row * 10 + column
    row <- match_position[1, 1] - 1  # Row (adjust for 0-based)
    col <- match_position[1, 2] - 1  # Column (adjust for 0-based)
    keyword_numeric <- c(keyword_numeric, row * 10 + col)
  }
}

# Step 3: Decrypt the ciphertext
plaintext <- ""
keyword_length <- length(keyword_numeric)

for (i in seq(1, length(ciphertext_pairs), by = 2)) {
  # Combine two digits from the ciphertext
  cipher_value <- ciphertext_pairs[i] * 10 + ciphertext_pairs[i + 1]
  
  # Adjust using the keyword
  key_adjustment <- keyword_numeric[((i - 1) %/% 2) %% keyword_length + 1]
  adjusted_value <- cipher_value - key_adjustment
  
  # Get row and column
  row <- floor(adjusted_value / 10)
  col <- adjusted_value %% 10
  
  # Add character to plaintext if within bounds
  if (!is.na(row) && row >= 0 && row <= 3 && !is.na(col) && col >= 0 && col <= 9) {
    letter <- Polybius[row + 1, col + 1]
    if (letter != " ") {
      plaintext <- paste0(plaintext, letter)
    }
  }
}

# Print the final plaintext
cat("Decrypted plaintext:\n", plaintext, "\n")



