#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use lib_q_core::{
Error,
Result,
};
use crate::core::SaturninCore;
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
use crate::simd::SimdOptimizedCore;
pub struct SaturninBlockCipher {
core: SaturninCore,
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
simd_core: SimdOptimizedCore,
}
impl SaturninBlockCipher {
pub fn new() -> Self {
let core = SaturninCore::new(10, 1).expect("Valid parameters");
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
let simd_core = SimdOptimizedCore::new(10, 1).expect("Valid parameters");
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
{
Self { core, simd_core }
}
#[cfg(not(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon")))]
{
Self { core }
}
}
pub const fn key_size() -> usize {
32
}
pub const fn block_size() -> usize {
32
}
pub fn encrypt_block(&self, key: &[u8], block: &[u8]) -> Result<Vec<u8>> {
if key.len() != Self::key_size() {
return Err(Error::InvalidKeySize {
expected: Self::key_size(),
actual: key.len(),
});
}
if block.len() != Self::block_size() {
return Err(Error::InvalidMessageSize {
max: Self::block_size(),
actual: block.len(),
});
}
let mut encrypted_block = block.to_vec();
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
{
let caps = self.simd_core.simd_capabilities();
if caps.has_simd() {
self.simd_core.encrypt_block(key, &mut encrypted_block)?;
} else {
self.core.encrypt_block(key, &mut encrypted_block)?;
}
}
#[cfg(not(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon")))]
{
self.core.encrypt_block(key, &mut encrypted_block)?;
}
Ok(encrypted_block)
}
pub fn decrypt_block(&self, key: &[u8], block: &[u8]) -> Result<Vec<u8>> {
if key.len() != Self::key_size() {
return Err(Error::InvalidKeySize {
expected: Self::key_size(),
actual: key.len(),
});
}
if block.len() != Self::block_size() {
return Err(Error::InvalidMessageSize {
max: Self::block_size(),
actual: block.len(),
});
}
let mut decrypted_block = block.to_vec();
#[cfg(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon"))]
{
let caps = self.simd_core.simd_capabilities();
if caps.has_simd() {
self.simd_core.decrypt_block(key, &mut decrypted_block)?;
} else {
self.core.decrypt_block(key, &mut decrypted_block)?;
}
}
#[cfg(not(any(feature = "simd", feature = "simd-avx2", feature = "simd-neon")))]
{
self.core.decrypt_block(key, &mut decrypted_block)?;
}
Ok(decrypted_block)
}
pub fn encrypt_ecb(&self, key: &[u8], blocks: &[u8]) -> Result<Vec<u8>> {
if key.len() != Self::key_size() {
return Err(Error::InvalidKeySize {
expected: Self::key_size(),
actual: key.len(),
});
}
if !blocks.len().is_multiple_of(Self::block_size()) {
return Err(Error::InvalidMessageSize {
max: blocks.len() - (blocks.len() % Self::block_size()),
actual: blocks.len(),
});
}
let mut encrypted = Vec::with_capacity(blocks.len());
for chunk in blocks.chunks(Self::block_size()) {
let mut block = chunk.to_vec();
self.core.encrypt_block(key, &mut block)?;
encrypted.extend_from_slice(&block);
}
Ok(encrypted)
}
pub fn decrypt_ecb(&self, key: &[u8], blocks: &[u8]) -> Result<Vec<u8>> {
if key.len() != Self::key_size() {
return Err(Error::InvalidKeySize {
expected: Self::key_size(),
actual: key.len(),
});
}
if !blocks.len().is_multiple_of(Self::block_size()) {
return Err(Error::InvalidMessageSize {
max: blocks.len() - (blocks.len() % Self::block_size()),
actual: blocks.len(),
});
}
let mut decrypted = Vec::with_capacity(blocks.len());
for chunk in blocks.chunks(Self::block_size()) {
let mut block = chunk.to_vec();
self.core.decrypt_block(key, &mut block)?;
decrypted.extend_from_slice(&block);
}
Ok(decrypted)
}
}
impl Default for SaturninBlockCipher {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use super::*;
#[test]
fn test_block_cipher_creation() {
let _cipher = SaturninBlockCipher::new();
assert_eq!(SaturninBlockCipher::key_size(), 32);
assert_eq!(SaturninBlockCipher::block_size(), 32);
}
#[test]
fn test_block_cipher_single_block() -> Result<()> {
let cipher = SaturninBlockCipher::new();
let key = vec![0u8; 32];
let plaintext = vec![0u8; 32];
let ciphertext = cipher.encrypt_block(&key, &plaintext)?;
assert_eq!(ciphertext.len(), 32);
assert_ne!(ciphertext, plaintext);
let decrypted = cipher.decrypt_block(&key, &ciphertext)?;
assert_eq!(decrypted, plaintext);
Ok(())
}
#[test]
fn test_block_cipher_ecb() -> Result<()> {
let cipher = SaturninBlockCipher::new();
let key = vec![0u8; 32];
let plaintext = vec![0u8; 64];
let ciphertext = cipher.encrypt_ecb(&key, &plaintext)?;
assert_eq!(ciphertext.len(), 64);
assert_ne!(ciphertext, plaintext);
let decrypted = cipher.decrypt_ecb(&key, &ciphertext)?;
assert_eq!(decrypted, plaintext);
Ok(())
}
#[test]
fn test_block_cipher_invalid_key_size() {
let cipher = SaturninBlockCipher::new();
let key = vec![0u8; 16]; let plaintext = vec![0u8; 32];
let result = cipher.encrypt_block(&key, &plaintext);
assert!(result.is_err());
}
#[test]
fn test_block_cipher_invalid_block_size() {
let cipher = SaturninBlockCipher::new();
let key = vec![0u8; 32];
let plaintext = vec![0u8; 16];
let result = cipher.encrypt_block(&key, &plaintext);
assert!(result.is_err());
}
#[test]
fn test_block_cipher_different_keys() -> Result<()> {
let cipher = SaturninBlockCipher::new();
let key1 = vec![0u8; 32];
let key2 = vec![1u8; 32];
let plaintext = vec![0u8; 32];
let ciphertext1 = cipher.encrypt_block(&key1, &plaintext)?;
let ciphertext2 = cipher.encrypt_block(&key2, &plaintext)?;
assert_ne!(ciphertext1, ciphertext2);
Ok(())
}
#[test]
fn test_block_cipher_different_plaintexts() -> Result<()> {
let cipher = SaturninBlockCipher::new();
let key = vec![0u8; 32];
let plaintext1 = vec![0u8; 32];
let plaintext2 = vec![1u8; 32];
let ciphertext1 = cipher.encrypt_block(&key, &plaintext1)?;
let ciphertext2 = cipher.encrypt_block(&key, &plaintext2)?;
assert_ne!(ciphertext1, ciphertext2);
Ok(())
}
}