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}