commit 5c87600c56d6fcd08a0c2295fc856c246a2bb7f6 Author: lionarius Date: Tue Sep 3 14:30:19 2024 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c264c38 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "information-security" +version = "0.1.0" +dependencies = [ + "anyhow", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0ef143e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "information-security" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.86" diff --git a/src/atbash.rs b/src/atbash.rs new file mode 100644 index 0000000..865fe36 --- /dev/null +++ b/src/atbash.rs @@ -0,0 +1,34 @@ +use crate::util; + +pub struct AtabashChipher { + alphabet: Vec, +} + +impl AtabashChipher { + pub fn new(alphabet: impl Into>) -> anyhow::Result { + let alphabet = alphabet.into(); + + util::verify_alphabet(&alphabet)?; + + Ok(Self { alphabet }) + } + + pub fn encode(&self, input: &str) -> anyhow::Result { + let mut output = String::with_capacity(input.len()); + + for c in input.chars() { + let index = self + .alphabet + .iter() + .position(|&x| x == c) + .ok_or(anyhow::anyhow!("cannot encode character {:?}", c))?; + output.push(self.alphabet[self.alphabet.len() - index - 1]); + } + + Ok(output) + } + + pub fn decode(&self, input: &str) -> anyhow::Result { + self.encode(input) + } +} diff --git a/src/caesar.rs b/src/caesar.rs new file mode 100644 index 0000000..ce17476 --- /dev/null +++ b/src/caesar.rs @@ -0,0 +1,56 @@ +use crate::util; + +pub struct CaesarCipher { + alphabet: Vec, + offset: i64, +} + +impl CaesarCipher { + pub fn new(alphabet: impl Into>, offset: i64) -> anyhow::Result { + let alphabet = alphabet.into(); + let offset = offset % alphabet.len() as i64; + + util::verify_alphabet(&alphabet)?; + + Ok(Self { alphabet, offset }) + } + + pub fn encode(&self, input: &str) -> anyhow::Result { + let mut output = String::with_capacity(input.len()); + + for c in input.chars() { + let index = self.get_index(c, self.offset)?; + output.push(self.alphabet[index]) + } + + Ok(output) + } + + pub fn decode(&self, input: &str) -> anyhow::Result { + let mut output = String::with_capacity(input.len()); + + for c in input.chars() { + let index = self.get_index(c, -self.offset)?; + output.push(self.alphabet[index]) + } + + Ok(output) + } + + fn get_index(&self, c: char, offset: i64) -> anyhow::Result { + let mut index = + self.alphabet + .iter() + .position(|&x| x == c) + .ok_or(anyhow::anyhow!("cannot encode character {:?}", c))? as i64 + + offset; + + while index < 0 { + index += self.alphabet.len() as i64; + } + + index %= self.alphabet.len() as i64; + + Ok(index as usize) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8dd1d3e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,14 @@ +mod atbash; +mod caesar; +mod util; + +fn main() -> anyhow::Result<()> { + let alphabet = "абвгдежзиклмнопрстуфхцчшщъыьэюя" + .chars() + .collect::>(); + let encoder = caesar::CaesarCipher::new(alphabet, 1)?; + println!("{}", encoder.encode("абвгд")?); + println!("{}", encoder.decode("бвгде")?); + + Ok(()) +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..00c33b2 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,17 @@ +pub fn verify_alphabet(alphabet: &[char]) -> anyhow::Result<()> { + if alphabet.len() < 2 { + return Err(anyhow::anyhow!( + "Alphabet must contain at least 2 characters" + )); + } + + let mut alphabet_set = std::collections::HashSet::new(); + for c in alphabet { + if alphabet_set.contains(c) { + return Err(anyhow::anyhow!("Alphabet contains duplicate characters")); + } + alphabet_set.insert(*c); + } + + Ok(()) +}