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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use regex::{Captures, Regex};
/// Bacon Cipher
///
/// The struct is generated througt new() funtion.
pub struct Bacon {
letters: (char, char),
}
impl Bacon {
/// Initialize a bacon cipher with a tuple of letters.
///
/// # Examples:
///
/// ```
/// use cienli::ciphers::bacon::Bacon;
///
/// let bacon = Bacon::new(('a', 'b')).unwrap();
/// ```
pub fn new(letters: (char, char)) -> Result<Bacon, &'static str> {
if letters.0 == letters.1 {
return Err("Error: Letters must be different from each other!!");
}
Ok(Bacon { letters })
}
/// Enciphers a message with the bacon cipher.
///
/// # Examples:
///
/// - Encipher with 'a' and 'b' letters:
/// ```
/// use cienli::ciphers::bacon::Bacon;
/// let bacon = Bacon::new(('a','b')).unwrap();
///
/// assert_eq!(
/// "aabbbaabaaababbababbabbba aababbaaababaaaaabaaabbabaaabb",
/// bacon.encipher("Hello Friend")
/// );
/// ```
///
/// - Encipher with '+' and '=' letters:
/// ```
/// use cienli::ciphers::bacon::Bacon;
/// let bacon = Bacon::new(('+', '=')).unwrap();
///
/// assert_eq!(
/// "++===++=+++=+==+=+==+===+ ++=+==+++=+=+++++=+++==+=+++==",
/// bacon.encipher("Hello Friend")
/// );
/// ```
pub fn encipher(&self, message: &str) -> String {
message
.to_ascii_uppercase()
.chars()
.map(|character| match character {
'A'..='Z' => format!("{:05b}", character as usize - 65)
.replace("0", &self.letters.0.to_string())
.replace("1", &self.letters.1.to_string()),
_ => character.to_string(),
})
.collect::<String>()
}
/// Deciphers a cipher with the bacon cipher.
///
/// # Examples:
///
/// - Decipher with 'a' and 'b' letters:
/// ```
/// use cienli::ciphers::bacon::Bacon;
/// let bacon = Bacon::new(('a', 'b')).unwrap();
///
/// assert_eq!(
/// "HELLO FRIEND",
/// bacon.decipher("aabbbaabaaababbababbabbba aababbaaababaaaaabaaabbabaaabb")
/// );
/// ```
///
/// - Decipher with '+' and '=' letters:
///
/// ```
/// use cienli::ciphers::bacon::Bacon;
/// let bacon = Bacon::new(('+', '=')).unwrap();
///
/// assert_eq!(
/// "HELLO FRIEND",
/// bacon.decipher("++===++=+++=+==+=+==+===+ ++=+==+++=+=+++++=+++==+=+++==")
/// );
/// ```
pub fn decipher(&self, message: &str) -> String {
let binary_message = message
.replace(&self.letters.0.to_string(), "0")
.replace(&self.letters.1.to_string(), "1");
let re = Regex::new(r"[01]{5}").unwrap();
let result = re.replace_all(&binary_message, |cap: &Captures| {
((u8::from_str_radix(&cap[0], 2).unwrap() + 65) as char).to_string()
});
result.to_string()
}
}
#[cfg(test)]
mod tests {
use super::Bacon;
#[test]
fn encipher_test() {
let bacon = Bacon::new(('a', 'b')).unwrap();
assert_eq!(
"aabbbaabaaababbababbabbba aababbaaababaaaaabaaabbabaaabb",
bacon.encipher("Hello Friend")
);
}
#[test]
fn decipher_test() {
let bacon = Bacon::new(('a', 'b')).unwrap();
assert_eq!(
"HELLO FRIEND",
bacon.decipher("aabbbaabaaababbababbabbba aababbaaababaaaaabaaabbabaaabb")
);
}
#[test]
fn encipher_with_different_letters() {
let bacon = Bacon::new(('+', '=')).unwrap();
assert_eq!(
"++===++=+++=+==+=+==+===+ ++=+==+++=+=+++++=+++==+=+++==",
bacon.encipher("Hello Friend")
);
}
#[test]
fn decipher_with_different_letters() {
let bacon = Bacon::new(('+', '=')).unwrap();
assert_eq!(
"HELLO FRIEND",
bacon.decipher("++===++=+++=+==+=+==+===+ ++=+==+++=+=+++++=+++==+=+++==")
);
}
#[test]
fn same_letters() {
assert!(Bacon::new(('a', 'a')).is_err());
}
}