1
0

initial commit

This commit is contained in:
2024-09-03 14:30:19 +03:00
commit 5c87600c56
7 changed files with 145 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

16
Cargo.lock generated Normal file
View File

@@ -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",
]

7
Cargo.toml Normal file
View File

@@ -0,0 +1,7 @@
[package]
name = "information-security"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.86"

34
src/atbash.rs Normal file
View File

@@ -0,0 +1,34 @@
use crate::util;
pub struct AtabashChipher {
alphabet: Vec<char>,
}
impl AtabashChipher {
pub fn new(alphabet: impl Into<Vec<char>>) -> anyhow::Result<Self> {
let alphabet = alphabet.into();
util::verify_alphabet(&alphabet)?;
Ok(Self { alphabet })
}
pub fn encode(&self, input: &str) -> anyhow::Result<String> {
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<String> {
self.encode(input)
}
}

56
src/caesar.rs Normal file
View File

@@ -0,0 +1,56 @@
use crate::util;
pub struct CaesarCipher {
alphabet: Vec<char>,
offset: i64,
}
impl CaesarCipher {
pub fn new(alphabet: impl Into<Vec<char>>, offset: i64) -> anyhow::Result<Self> {
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<String> {
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<String> {
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<usize> {
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)
}
}

14
src/main.rs Normal file
View File

@@ -0,0 +1,14 @@
mod atbash;
mod caesar;
mod util;
fn main() -> anyhow::Result<()> {
let alphabet = "абвгдежзиклмнопрстуфхцчшщъыьэюя"
.chars()
.collect::<Vec<_>>();
let encoder = caesar::CaesarCipher::new(alphabet, 1)?;
println!("{}", encoder.encode("абвгд")?);
println!("{}", encoder.decode("бвгде")?);
Ok(())
}

17
src/util.rs Normal file
View File

@@ -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(())
}