cipher_crypt/common/
substitute.rs

1//! Contains substitution methods that are used by a variety of ciphers
2//!
3use super::alphabet;
4use super::alphabet::Alphabet;
5
6/// Performs a shift substitution of letters within a piece of text based on the index of them
7/// within the alphabet.
8///
9/// This substitution is defined by the closure `calc_index(ti)`.
10///     * ti = the index of the character to shift
11///     * note; the closure should shift the value set within the bounds of the standard alphabet
12pub fn shift_substitution<F>(text: &str, calc_index: F) -> String
13where
14    F: Fn(usize) -> usize,
15{
16    let mut s_text = String::new();
17    for c in text.chars() {
18        //Find the index of the character in the alphabet (if it exists in there)
19        let pos = alphabet::STANDARD.find_position(c);
20        match pos {
21            Some(pos) => {
22                let si = calc_index(pos); //Calculate substitution index
23                s_text.push(alphabet::STANDARD.get_letter(si, c.is_uppercase()));
24            }
25            None => s_text.push(c), //Push non-alphabetic chars 'as-is'
26        }
27    }
28
29    s_text
30}
31
32/// Performs a poly-substitution on a piece of text based on the index of its characters
33/// (within the alphabet) and the keystream `k`.
34///
35/// This substitution is defined by the closure `calc_index(ti, ki)`.
36/// Where:
37///     * ti = the index of the character to shift
38///     * ki = the index of the next key character in the stream
39pub fn key_substitution<F>(text: &str, keystream: &str, calc_index: F) -> String
40where
41    F: Fn(usize, usize) -> usize,
42{
43    let mut s_text = String::new();
44    let mut keystream_iter = keystream.chars().peekable();
45    for tc in text.chars() {
46        //Find the index of the character in the alphabet (if it exists in there)
47        let tpos = alphabet::STANDARD.find_position(tc);
48        match tpos {
49            Some(ti) => {
50                if let Some(kc) = keystream_iter.peek() {
51                    if let Some(ki) = alphabet::STANDARD.find_position(*kc) {
52                        //Calculate the index and retrieve the letter to substitute
53                        let si = calc_index(ti, ki);
54                        s_text.push(alphabet::STANDARD.get_letter(si, tc.is_uppercase()));
55                    } else {
56                        panic!("Keystream contains a non-alphabetic symbol.");
57                    }
58                } else {
59                    panic!("Keystream is not large enough for full substitution of message.");
60                }
61                keystream_iter.next();
62            }
63            None => s_text.push(tc), //Push non-alphabetic chars 'as-is'
64        }
65    }
66
67    s_text
68}