ferric_crypto_lib 0.2.7

A library for Ferric Crypto
Documentation
use crate::crypto_systems::ceasar::Ceasar;
use crate::error::CeasarError;
use crate::prelude::ALPHABET_LEN;
use crate::utils::{decode_digit, encode_char, BaseString, EncodedString, StringType};
use crate::Traits::Encrypt;
use rayon::prelude::*;

impl Encrypt<CeasarError, BaseString, BaseString> for Ceasar {
    /// Encrypts a string using the Caesar cipher.
    ///
    /// This function shifts each letter in the input string by a fixed number of positions in the alphabet,
    /// wrapping around to the beginning if necessary. Non-alphabetic characters are left unchanged.
    /// The shift value is determined by the `shift` field of the `Ceasar` struct.
    ///
    /// # Arguments
    ///
    /// * `input` - A `String` that holds the text to be encrypted.
    ///
    /// # Returns
    ///
    /// * A `Result<String, CeasarError>` which is `Ok` if the encryption is successful, and `Err` otherwise.
    ///   The `Ok` variant contains the encrypted text, and the `Err` variant contains an error type.
    ///
    /// # Example
    ///
    /// ```
    /// # use ferric_crypto_lib::crypto_systems::ceasar::Ceasar;
    /// # use ferric_crypto_lib::Traits::Encrypt;
    /// let ceasar = Ceasar::new(3);
    /// let result = ceasar.encrypt("hello".into()).unwrap();
    /// assert_eq!(result, "KHOOR".into());
    /// ```
    fn encrypt(&self, input: BaseString) -> Result<BaseString, CeasarError> {
        let encoded_input = input.encode()?;

        // Use par_iter to perform the encryption in parallel, then collect into Vec<usize>
        let encrypted_data: Vec<usize> = encoded_input
            .par_iter()
            .map(|&x| (x + self.shift) % *ALPHABET_LEN)
            .collect(); // TODO: would be good if this returned a EncodedString directly!

        // Now convert encrypted_data into EncodedString
        let encrypted_input = EncodedString::new(encrypted_data, StringType::Standard);

        // Code below will be simplified once BaseString is complete
        // Finally, decode the encrypted input back into a string
        let decoded = encrypted_input.decode()?;

        Ok(decoded.to_uppercase())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::error::CharacterParseError::InvalidCharacter;
    use crate::Traits::Encrypt;

    #[test]
    fn encrypts_lowercase() {
        let cipher = Ceasar { shift: 3 };
        let result = cipher.encrypt("hello".into()).unwrap();
        assert_eq!(result, "KHOOR".into());
    }

    #[test]
    fn encrypts_uppercase() {
        let cipher = Ceasar { shift: 3 };
        let result = cipher.encrypt("HELLO".into()).unwrap();
        assert_eq!(result, "KHOOR".into());
    }

    #[test]
    fn encrypts_wrap() {
        let cipher = Ceasar { shift: 4 };
        let result = cipher.encrypt("zoo".into()).unwrap();
        assert_eq!(result, "ASS".into());
    }

    #[test]
    fn encrypts_non_alphabetic_characters() {
        let cipher = Ceasar { shift: 3 };
        let result = match cipher.encrypt("123!@#".into()) {
            Ok(_) => panic!("Should return error"),
            Err(e) => e,
        };
    }

    #[test]
    fn encrypts_empty_string() {
        let cipher = Ceasar { shift: 3 };
        let result = cipher.encrypt("".into()).unwrap();
        assert_eq!(result, "".into());
    }

    #[test]
    fn encrypts_with_zero_shift() {
        let cipher = Ceasar { shift: 0 };
        let result = cipher.encrypt("hello".into()).unwrap();
        assert_eq!(result, "HELLO".into());
    }

    #[test]
    fn encrypts_with_large_shift() {
        let cipher = Ceasar { shift: 100 };
        let result = cipher.encrypt("hello".into()).unwrap();
        assert_eq!(result, "YUÖÖC".into());
    }

    #[test]
    fn encrypts_mixed_case() {
        let cipher = Ceasar { shift: 3 };
        let result = cipher.encrypt("HelloVVorld".into()).unwrap();
        assert_eq!(result, "KHOORZZRUOG".into());
    }
}