use crate::{
errors::SteganographyError,
image::lossless::bpcs::{
bit_plane::{BitPlane, PLANE_SIZE, USIZE_PLANE_SIZE},
dynamic_prefix::{
data_bits_from_prefixed_planes, get_prefixed_planes, num_of_prefixed_planes_for_n_bits,
prefix_length,
},
},
utils::bit_operations_utils::{USIZE_BIT_DEPTH, bits_to_usize, unsigned_int_to_bits},
};
pub(crate) const MESSAGE_LENGTH_IV_BIT_NUMBER: usize = USIZE_BIT_DEPTH;
pub(crate) const MESSAGE_REMNANT_IV_BIT_NUMBER: usize = USIZE_BIT_DEPTH;
pub(crate) fn calculate_iv_plane_number(min_alpha: f64) -> usize {
num_of_prefixed_planes_for_n_bits(MESSAGE_LENGTH_IV_BIT_NUMBER, prefix_length(min_alpha))
+ num_of_prefixed_planes_for_n_bits(MESSAGE_REMNANT_IV_BIT_NUMBER, prefix_length(min_alpha))
}
pub(crate) fn build_message_length_iv(message_plane_length: usize) -> Vec<bool> {
unsigned_int_to_bits(message_plane_length)
}
pub(crate) fn build_message_remnant_iv(remnant_bit_number: usize) -> Vec<bool> {
assert!(remnant_bit_number <= (USIZE_PLANE_SIZE * USIZE_PLANE_SIZE));
unsigned_int_to_bits(remnant_bit_number)
}
pub(crate) fn build_iv_planes(
min_alpha: f64,
message_plane_length: usize,
remnant_bit_number: usize,
) -> Vec<BitPlane> {
let mut iv_planes: Vec<BitPlane> = Vec::new();
iv_planes.extend(get_prefixed_planes(
build_message_length_iv(message_plane_length),
min_alpha,
));
iv_planes.extend(get_prefixed_planes(
build_message_remnant_iv(remnant_bit_number),
min_alpha,
));
iv_planes
}
pub(crate) fn build_conjugation_map_planes(
conjugation_map: Vec<bool>,
min_alpha: f64,
) -> Vec<BitPlane> {
get_prefixed_planes(conjugation_map, min_alpha)
}
pub(crate) fn extract_iv_data_from_iv_planes(
mut planes: Vec<BitPlane>,
min_alpha: f64,
) -> Result<(usize, usize), SteganographyError> {
let prefix_length = prefix_length(min_alpha);
let msg_len_iv_plane_length =
num_of_prefixed_planes_for_n_bits(MESSAGE_LENGTH_IV_BIT_NUMBER, prefix_length);
let msg_rem_iv_plane_length =
num_of_prefixed_planes_for_n_bits(MESSAGE_REMNANT_IV_BIT_NUMBER, prefix_length);
let length_iv_bits = data_bits_from_prefixed_planes(
planes.drain(0..msg_len_iv_plane_length).collect(),
min_alpha,
)
.drain(0..MESSAGE_LENGTH_IV_BIT_NUMBER) .collect::<Vec<bool>>();
let message_plane_length = bits_to_usize(length_iv_bits.try_into().unwrap());
let remnant_iv_bits = data_bits_from_prefixed_planes(
planes.drain(0..msg_rem_iv_plane_length).collect(),
min_alpha,
)
.drain(0..MESSAGE_REMNANT_IV_BIT_NUMBER)
.collect::<Vec<bool>>();
let message_remnant_length = bits_to_usize(remnant_iv_bits.try_into().unwrap());
if message_remnant_length > USIZE_PLANE_SIZE * USIZE_PLANE_SIZE {
let bits_per_plane = PLANE_SIZE * PLANE_SIZE;
return Err(SteganographyError::InvalidIVData(String::from(format!(
"Message remnant IV can't be more than the amount of bits per plane ({message_remnant_length} > {bits_per_plane})"
))));
}
Ok((message_plane_length, message_remnant_length))
}
pub(crate) fn extract_conj_map_data_from_conj_map_planes(
planes: Vec<BitPlane>,
min_alpha: f64,
message_plane_length: usize,
) -> Result<Vec<bool>, SteganographyError> {
let conjugation_map_data = data_bits_from_prefixed_planes(planes, min_alpha)
.drain(0..message_plane_length) .collect::<Vec<bool>>();
Ok(conjugation_map_data)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::image::lossless::bpcs::dynamic_prefix::get_n_random_bools;
#[test]
fn test_circular_iv_generation_and_data_extraction() -> Result<(), Box<dyn std::error::Error>> {
let (min_alpha, message_plane_length, remnant_bit_number) = (0.3, 65832usize, 4);
let iv_planes = build_iv_planes(min_alpha, message_plane_length, remnant_bit_number);
assert_eq!(
extract_iv_data_from_iv_planes(iv_planes, min_alpha)?,
(message_plane_length, remnant_bit_number)
);
Ok(())
}
#[test]
fn test_circular_conjugation_map_generation_and_data_extraction()
-> Result<(), Box<dyn std::error::Error>> {
let message_plane_length = 47usize;
let min_alpha = 0.3f64;
let conjugation_map = get_n_random_bools(message_plane_length);
let conjugation_map_planes =
build_conjugation_map_planes(conjugation_map.clone(), min_alpha);
assert_eq!(
extract_conj_map_data_from_conj_map_planes(
conjugation_map_planes,
min_alpha,
message_plane_length
)?,
conjugation_map
);
Ok(())
}
}