1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::sync::Arc;

use crate::utils::alphabets::Alphabet;
use crate::utils::alphabets::split_bytes_by_characters_representation;
use crate::utils::alphabets::uniffy_opcode_group;

pub struct ColumnarTranspositionAlgorithm {
    alphabet: Arc<Alphabet>,
}

impl ColumnarTranspositionAlgorithm {
    pub fn new(alphabet: Arc<Alphabet>) -> Self {
        ColumnarTranspositionAlgorithm { 
            alphabet: alphabet
         }
    }
    
    /// Encrypt the `plain_text` with the columnar transposition encryption algorithm `key`.
    ///
    /// An array with lines of size `key` is created with the `plain_text` argument. The cipher text is producted as output with reading the plain text, column by column, from top to bot, from lefgt to right.
    /// The custom alphabet has been put in the constructor of the struct CaesarNumberAlgorithm.
    /// 
    /// ```
    /// use cryptatools_core::utils::alphabets::Alphabet;
    /// use cryptatools_core::utils::convert::{Encode, Decode};
    /// use cryptatools_core::cryptography::classical::encryption::transpositional_ciphers::columnar_transposition::ColumnarTranspositionAlgorithm;
    /// 
    /// let printable_ascii_alphabet = Alphabet::new_empty().ascii_printable_only_encoding();
    /// let key = 6;
    /// let plain_text = "all work and no play makes johnny a dull boy".replace(" ", "").to_uppercase();
    /// let plain_text_opcodes = Encode::encode(&printable_ascii_alphabet, String::from(plain_text));
    /// let mut columnar = ColumnarTranspositionAlgorithm::new(printable_ascii_alphabet.into());
    /// let cipher_text_opcodes = columnar.encrypt(plain_text_opcodes, 6);
    /// let ascii_plain_text = Decode::from_u8_to_ascii(cipher_text_opcodes);
    /// 
    /// assert_eq!(ascii_plain_text, "AKPKNLLALENLLNASYBWDYJAOONMODYROAHU");
    /// ```
    pub fn encrypt(&self, plain_text: Vec<u8>, key: u32) -> Vec<u8> {
        let plain_text_group = split_bytes_by_characters_representation(&self.alphabet, plain_text);
        let columns: Vec<Vec<u8>> = (0..key)
            .flat_map(|collumn| (collumn..plain_text_group.len() as u32)
                .step_by(key as usize)
                .map(|i| plain_text_group[i as usize].clone()))
            .collect();

        uniffy_opcode_group(columns)
    }
    
    /// Decrypt the `cipher_text` with the columnar transposition encryption algorithm `key`.
    /// 
    /// Exatcly same operation as `encrypt` method.
    /// 
    /// ```
    /// use cryptatools_core::utils::alphabets::Alphabet;
    /// use cryptatools_core::utils::convert::{Encode, Decode};
    /// use cryptatools_core::cryptography::classical::encryption::transpositional_ciphers::columnar_transposition::ColumnarTranspositionAlgorithm;
    ///
    /// let printable_ascii_alphabet = Alphabet::new_empty().ascii_printable_only_encoding();
    /// let mut columnar = ColumnarTranspositionAlgorithm::new(printable_ascii_alphabet.into());
    /// let cipher_text_ascii = String::from("AKPKNLLALENLLNASYBWDYJAOONMODYROAHU");
    /// let opcodes_plain_text = Encode::from_ascii_to_u8(cipher_text_ascii);
    /// let key = 6;
    /// let plain_text_opcodes = columnar.decrypt(opcodes_plain_text, key);
    /// let ascii_plain_text = Decode::from_u8_to_ascii(plain_text_opcodes);
    /// 
    /// assert_eq!(ascii_plain_text, "all work and no play makes johnny a dull boy".replace(" ", "").to_uppercase());
    /// ```
    pub fn decrypt(&self, cipher_text: Vec<u8>, key: u32) -> Vec<u8> {
        let cipher_text_group = split_bytes_by_characters_representation(&self.alphabet, cipher_text);
        let columns: Vec<Vec<u8>> = (0..key)
            .flat_map(|collumn| (collumn..cipher_text_group.len() as u32)
                .step_by(key as usize)
                .map(|i| cipher_text_group[i as usize].clone()))
            .collect();

        uniffy_opcode_group(columns)
    }
}