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
use crate::{input, Cipher, CipherInputError, CipherResult};
pub struct PolybiusSquare {
key: String,
chars: String,
}
impl PolybiusSquare {
pub fn new(key: &str, chars: &str) -> Self {
input::is_ascii(key).expect("`key` must be valid ascii");
input::no_repeated_chars(key).expect("`key` cannot contain repeated chars");
input::is_ascii(chars).expect("`chars` must be valid ascii");
input::no_repeated_chars(chars).expect("`chars` cannot contain repeated chars");
assert_eq!(
key.len(),
chars.len() * chars.len(),
"`chars` must be of length sqrt(key.len())"
);
Self {
key: String::from(key),
chars: String::from(chars),
}
}
}
impl Cipher for PolybiusSquare {
fn encipher(&self, ptext: &str) -> CipherResult {
input::in_alphabet(ptext, &self.key)?;
let chars = self.chars.as_bytes();
let mut ctext: Vec<u8> = Vec::with_capacity(ptext.len());
for c in ptext.bytes() {
let i = match self.key.find(move |j| j == c as char) {
Some(val) => val,
None => return Err(CipherInputError::NotInAlphabet),
};
ctext.push(chars[i / chars.len()]);
ctext.push(chars[i % chars.len()]);
}
Ok(String::from_utf8(ctext).unwrap())
}
fn decipher(&self, ctext: &str) -> CipherResult {
input::in_alphabet(ctext, &self.chars)?;
if ctext.len() % 2 != 0 {
return Err(CipherInputError::BadInput(String::from(
"`ctext` must contain an even number of chars",
)));
}
let key = self.key.as_bytes();
let ctext = ctext.as_bytes();
let mut ptext: Vec<u8> = Vec::with_capacity(ctext.len());
for i in (0..ctext.len()).step_by(2) {
let y = match self.chars.find(|c| c == ctext[i] as char) {
Some(val) => val,
None => return Err(CipherInputError::NotInAlphabet),
};
let x = match self.chars.find(|c| c == ctext[i + 1] as char) {
Some(val) => val,
None => return Err(CipherInputError::NotInAlphabet),
};
ptext.push(key[y * self.chars.len() + x]);
}
Ok(String::from_utf8(ptext).unwrap())
}
}