/ src / main.rs
main.rs
  1  use std::collections::HashMap;
  2  use std::env;
  3  use std::fs;
  4  use std::path::Path;
  5  use rand::{Rng, SeedableRng};
  6  use rand::rngs::StdRng;
  7  use regex::Regex;
  8  use hmac::{Hmac, Mac};
  9  use sha2::Sha256;
 10  use base64::{engine::general_purpose, Engine as _};
 11  
 12  type HmacSha256 = Hmac<Sha256>;
 13  
 14  struct WordDictionaries {
 15      nouns: Vec<String>,
 16      verbs: Vec<String>,
 17      adjectives: Vec<String>,
 18      adverbs: Vec<String>,
 19      prepositions: Vec<String>,
 20      articles: Vec<String>,
 21      conjunctions: Vec<String>,
 22      pronouns: Vec<String>,
 23      proper_nouns: Vec<String>,
 24  }
 25  
 26  impl WordDictionaries {
 27      fn new() -> Self {
 28          WordDictionaries {
 29              nouns: Self::load_words("dictionaries/nouns.txt"),
 30              verbs: Self::load_words("dictionaries/verbs.txt"),
 31              adjectives: Self::load_words("dictionaries/adjectives.txt"),
 32              adverbs: Self::load_words("dictionaries/adverbs.txt"),
 33              prepositions: Self::load_words("dictionaries/prepositions.txt"),
 34              articles: Self::load_words("dictionaries/articles.txt"),
 35              conjunctions: Self::load_words("dictionaries/conjunctions.txt"),
 36              pronouns: Self::load_words("dictionaries/pronouns.txt"),
 37              proper_nouns: Self::load_words("dictionaries/proper_nouns.txt"),
 38          }
 39      }
 40  
 41      fn load_words(filename: &str) -> Vec<String> {
 42          let path = Path::new(filename);
 43          if !path.exists() {
 44              eprintln!("Warning: Dictionary file '{}' not found.", filename);
 45              return Vec::new();
 46          }
 47  
 48          let content = match fs::read_to_string(path) {
 49              Ok(c) => c,
 50              Err(err) => {
 51                  eprintln!("Error reading '{}': {}", filename, err);
 52                  return Vec::new();
 53              }
 54          };
 55  
 56          content
 57              .lines()
 58              .filter_map(|line| {
 59                  let word = line.trim();
 60                  if word.is_empty() {
 61                      None
 62                  } else {
 63                      Some(word.to_lowercase())
 64                  }
 65              })
 66              .collect()
 67      }
 68  
 69      fn get_dictionary(&self, pos: &str) -> Option<&Vec<String>> {
 70          match pos {
 71              "noun" => Some(&self.nouns),
 72              "verb" => Some(&self.verbs),
 73              "adjective" => Some(&self.adjectives),
 74              "adverb" => Some(&self.adverbs),
 75              "preposition" => Some(&self.prepositions),
 76              "article" => Some(&self.articles),
 77              "conjunction" => Some(&self.conjunctions),
 78              "pronoun" => Some(&self.pronouns),
 79              "proper_noun" => Some(&self.proper_nouns),
 80              _ => None,
 81          }
 82      }
 83  
 84      fn get_pos(&self, word: &str) -> Option<String> {
 85          let word = word.to_lowercase();
 86          if self.nouns.contains(&word) {
 87              Some("noun".to_string())
 88          } else if self.verbs.contains(&word) {
 89              Some("verb".to_string())
 90          } else if self.adjectives.contains(&word) {
 91              Some("adjective".to_string())
 92          } else if self.adverbs.contains(&word) {
 93              Some("adverb".to_string())
 94          } else if self.prepositions.contains(&word) {
 95              Some("preposition".to_string())
 96          } else if self.articles.contains(&word) {
 97              Some("article".to_string())
 98          } else if self.conjunctions.contains(&word) {
 99              Some("conjunction".to_string())
100          } else if self.pronouns.contains(&word) {
101              Some("pronoun".to_string())
102          } else if self.proper_nouns.contains(&word) {
103              Some("proper_noun".to_string())
104          } else {
105              None
106          }
107      }
108  }
109  
110  struct GrammaticalCipher {
111      dictionaries: WordDictionaries,
112      encrypt_mappings: HashMap<(String, u64), HashMap<String, String>>,
113      decrypt_mappings: HashMap<(String, u64), HashMap<String, String>>,
114  }
115  
116  impl GrammaticalCipher {
117      fn new() -> Self {
118          GrammaticalCipher {
119              dictionaries: WordDictionaries::new(),
120              encrypt_mappings: HashMap::new(),
121              decrypt_mappings: HashMap::new(),
122          }
123      }
124  
125      fn encrypt(&mut self, sentence: &str, key: u64) -> String {
126          let encrypted = self.process(sentence, key, true);
127          let hmac = Self::generate_hmac(&encrypted, key);
128          format!("{} | {}", encrypted, hmac)
129      }
130  
131      fn decrypt(&mut self, input: &str, key: u64) -> String {
132          let parts: Vec<&str> = input.rsplitn(2, " | ").collect();
133          if parts.len() != 2 {
134              return "Error: Invalid encrypted format. Expected format: TEXT | HMAC".to_string();
135          }
136          let provided_hmac = parts[0];
137          let encrypted_text = parts[1];
138  
139          let calculated_hmac = Self::generate_hmac(encrypted_text, key);
140          if provided_hmac != calculated_hmac {
141              return "⚠️ Warning: Message has been tampered with or the key is incorrect.".to_string();
142          }
143  
144          self.process(encrypted_text, key, false)
145      }
146  
147      fn generate_hmac(data: &str, key: u64) -> String {
148          let mut mac = HmacSha256::new_from_slice(&key.to_le_bytes()).expect("HMAC init failed");
149          mac.update(data.as_bytes());
150          let result = mac.finalize();
151          let code_bytes = result.into_bytes();
152          general_purpose::STANDARD.encode(code_bytes)
153      }
154  
155      fn process(&mut self, sentence: &str, key: u64, encrypting: bool) -> String {
156          let re = Regex::new(r"[\w'-]+|[^\w\s]").unwrap();
157          let tokens: Vec<&str> = re.find_iter(sentence).map(|m| m.as_str()).collect();
158          let mut result = String::new();
159          let mut prev_was_word = false;
160  
161          for token in tokens {
162              let is_word = token.chars().all(|c| c.is_alphanumeric() || c == '\'' || c == '-');
163              let lower = token.to_lowercase();
164  
165              if is_word {
166                  if prev_was_word {
167                      result.push(' ');
168                  }
169  
170                  let mut stemmed = lower.clone();
171                  let mut matched_pos = self.dictionaries.get_pos(&stemmed);
172  
173                  if matched_pos.is_none() {
174                      let guess_stem = self.stem_verb(&lower);
175                      if guess_stem != lower {
176                          stemmed = guess_stem;
177                          matched_pos = self.dictionaries.get_pos(&stemmed);
178                      }
179                  }
180  
181                  if let Some(pos) = matched_pos {
182                      self.ensure_mappings_exist(&pos, key);
183                      let mapped = if encrypting {
184                          self.encrypt_mappings.get(&(pos.clone(), key))
185                              .and_then(|m| m.get(&stemmed))
186                              .cloned()
187                      } else {
188                          self.decrypt_mappings.get(&(pos.clone(), key))
189                              .and_then(|m| m.get(&stemmed))
190                              .cloned()
191                      };
192  
193                      let final_word = if let Some(mapped_word) = mapped {
194                          if token.chars().next().unwrap().is_uppercase() {
195                              let mut chars = mapped_word.chars();
196                              match chars.next() {
197                                  None => String::new(),
198                                  Some(first_char) => first_char.to_uppercase().collect::<String>() + chars.as_str(),
199                              }
200                          } else {
201                              mapped_word
202                          }
203                      } else {
204                          token.to_string()
205                      };
206  
207                      result.push_str(&final_word);
208                  } else {
209                      result.push_str(token);
210                  }
211                  prev_was_word = true;
212              } else {
213                  result.push_str(token);
214                  prev_was_word = false;
215              }
216          }
217  
218          result
219      }
220  
221      fn ensure_mappings_exist(&mut self, pos: &str, key: u64) {
222          let key_pos = (pos.to_string(), key);
223          if self.encrypt_mappings.contains_key(&key_pos) && self.decrypt_mappings.contains_key(&key_pos) {
224              return;
225          }
226          self.create_mappings(&key_pos);
227      }
228  
229      fn create_mappings(&mut self, key_pos: &(String, u64)) {
230          let (pos, key) = key_pos;
231          let mut rng = StdRng::seed_from_u64(*key);
232  
233          if let Some(dict) = self.dictionaries.get_dictionary(pos) {
234              let mut encrypt_map = HashMap::new();
235              let mut decrypt_map = HashMap::new();
236  
237              if dict.is_empty() {
238                  return;
239              }
240  
241              let mut shuffled = dict.clone();
242              for i in (1..shuffled.len()).rev() {
243                  let j = rng.gen_range(0..=i);
244                  shuffled.swap(i, j);
245              }
246  
247              for (i, word) in dict.iter().enumerate() {
248                  let encrypted = &shuffled[i];
249                  encrypt_map.insert(word.clone(), encrypted.clone());
250                  decrypt_map.insert(encrypted.clone(), word.clone());
251              }
252  
253              self.encrypt_mappings.insert(key_pos.clone(), encrypt_map);
254              self.decrypt_mappings.insert(key_pos.clone(), decrypt_map);
255          }
256      }
257  
258      fn stem_verb(&self, word: &str) -> String {
259          let lower = word.to_lowercase();
260          if self.dictionaries.verbs.contains(&lower) {
261              return lower;
262          }
263  
264          let mut w = lower.clone();
265  
266          if w.ends_with("ies") && w.len() > 4 {
267              w = format!("{}y", &w[..w.len() - 3]);
268          } else if w.ends_with("ied") && w.len() > 4 {
269              w = format!("{}y", &w[..w.len() - 3]);
270          } else if w.ends_with("ing") && w.len() > 5 {
271              w = w[..w.len() - 3].to_string();
272          } else if w.ends_with("ed") && w.len() > 4 {
273              w = w[..w.len() - 2].to_string();
274          } else if w.ends_with("en") && w.len() > 4 {
275              w = w[..w.len() - 2].to_string();
276          } else if w.ends_with("es") && w.len() > 4 {
277              w = w[..w.len() - 2].to_string();
278          } else if w.ends_with('s') && w.len() > 3 {
279              w = w[..w.len() - 1].to_string();
280          }
281  
282          if self.dictionaries.verbs.contains(&w) {
283              w
284          } else {
285              lower
286          }
287      }
288  }
289  
290  fn main() {
291      let args: Vec<String> = env::args().collect();
292  
293      if args.len() < 4 {
294          eprintln!("Usage: {} [encrypt|decrypt] [key] [text...]", args[0]);
295          std::process::exit(1);
296      }
297  
298      let operation = &args[1];
299      let key_str = &args[2];
300      let input_text = args[3..].join(" ");
301  
302      let key = match key_str.parse::<u64>() {
303          Ok(k) => k,
304          Err(_) => {
305              eprintln!("Error: Key must be a positive integer");
306              std::process::exit(1);
307          }
308      };
309  
310      let mut cipher = GrammaticalCipher::new();
311  
312      match operation.as_str() {
313          "encrypt" => {
314              let output = cipher.encrypt(&input_text, key);
315              println!("Original:  {}", input_text);
316              println!("Encrypted: {}", output);
317          },
318          "decrypt" => {
319              let output = cipher.decrypt(&input_text, key);
320              println!("Encrypted: {}", input_text);
321              println!("Decrypted: {}", output);
322          },
323          _ => {
324              eprintln!("Error: Unknown operation. Use 'encrypt' or 'decrypt'");
325              std::process::exit(1);
326          }
327      }
328  }