//! Provides basic key-based encryption for financial data.
//! 
//! **Please note** that the encryption algorithm implemented here is not considered perfectly secure.
//! The algorithm implemented here is similar to that of the Vigenere cipher with an added key scrambling.

use sha256::digest;
use hex::decode;


/// Scrambles a key.
fn scramble(key: &mut Vec<u8>) {
    for i in 0..key.len() {
        let j: usize = (key[i] as usize) % key.len();

        // Switch `key[i]` and `key[j]`
        let temp = key[i];
        key[i] = key[j];
        key[j] = temp;
    }
}


/// Encrypts a bytestream using a key.
pub fn encrypt(plaintext: Vec<u8>, key: String) -> Vec<u8> {
    // Note: it's OK to use `Result::unwrap()` here because we know that `sha256::digest`
    // is guaranteed to return us proper hexadecial digits
    let mut hash: Vec<u8> = decode(digest(key)).unwrap();

    // `hash` should be at least as long as `plaintext`
    while hash.len() < plaintext.len() {
        let mut next = hash.clone();
        hash.append(&mut next);
    }

    // Scramble the key
    scramble(&mut hash);

    let mut ciphertext = Vec::new();

    for (i, j) in plaintext.iter().zip(hash.iter()) {
        ciphertext.push(i ^ j);
    }

    ciphertext
}


/// Decrypts a bytestream using a key.
pub fn decrypt(ciphertext: Vec<u8>, key: String) -> Vec<u8> {
    // Note: it's OK to use `Result::unwrap()` here because we know that `sha256::digest`
    // is guaranteed to return us proper hexadecial digits
    let mut hash: Vec<u8> = decode(digest(key)).unwrap();

    // `hash` should be at least as long as `ciphertext`
    while hash.len() < ciphertext.len() {
        let mut next = hash.clone();
        hash.append(&mut next);
    }

    // Scramble the key
    scramble(&mut hash);

    let mut plaintext = Vec::new();

    for (i, j) in ciphertext.iter().zip(hash.iter()) {
        plaintext.push(i ^ j);
    }

    plaintext
}