use cipher::{
Block, BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, Iv, IvSizeUser, Key, KeyInit,
KeyIvInit, KeySizeUser, consts::U16, consts::U32, typenum::Sum,
};
use core::fmt;
use hybrid_array::ArraySize;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
const BLOCK_SIZE: usize = 16;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
DataTooShort,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DataTooShort => write!(f, "Data must be at least 16 bytes for EME2"),
}
}
}
impl core::error::Error for Error {}
#[inline]
fn xor_blocks(out: &mut [u8; BLOCK_SIZE], a: &[u8; BLOCK_SIZE], b: &[u8; BLOCK_SIZE]) {
for i in 0..BLOCK_SIZE {
out[i] = a[i] ^ b[i];
}
}
#[inline]
fn xor_into(out: &mut [u8; BLOCK_SIZE], b: &[u8; BLOCK_SIZE]) {
for (out_byte, b_byte) in out.iter_mut().zip(b.iter()) {
*out_byte ^= *b_byte;
}
}
#[inline]
fn mult_by_two(val: &[u8; BLOCK_SIZE]) -> [u8; BLOCK_SIZE] {
let mut res = [0u8; BLOCK_SIZE];
let mut b0 = [0u8; 8];
b0.copy_from_slice(&val[0..8]);
let mut v0 = u64::from_le_bytes(b0);
let mut b1 = [0u8; 8];
b1.copy_from_slice(&val[8..16]);
let mut v1 = u64::from_le_bytes(b1);
let carry_out = v1 >> 63;
v1 = (v1 << 1) | (v0 >> 63);
v0 <<= 1;
let mask = 0u64.wrapping_sub(carry_out);
v0 ^= 0x87 & mask;
res[0..8].copy_from_slice(&v0.to_le_bytes());
res[8..16].copy_from_slice(&v1.to_le_bytes());
res
}
#[inline]
fn encrypt_block<C>(cipher: &C, block: &mut [u8; 16])
where
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
{
let mut b: Block<C> = (*block).into();
cipher.encrypt_block(&mut b);
*block = b.into();
}
#[inline]
fn decrypt_block<C>(cipher: &C, block: &mut [u8; 16])
where
C: BlockCipherDecrypt + BlockSizeUser<BlockSize = U16>,
{
let mut b: Block<C> = (*block).into();
cipher.decrypt_block(&mut b);
*block = b.into();
}
#[inline]
fn block_to_array<C>(block: &Block<C>) -> [u8; BLOCK_SIZE]
where
C: BlockSizeUser<BlockSize = U16>,
{
(*block).into()
}
#[derive(Clone)]
#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))]
pub struct Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
#[cfg_attr(feature = "zeroize", zeroize(skip))]
cipher: C,
key2: Block<C>,
key3: Block<C>,
tweak: Block<C>,
}
impl<C> BlockSizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type BlockSize = U16;
}
impl<C> KeySizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type KeySize = Sum<C::KeySize, U32>;
}
impl<C> KeyInit for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeyInit,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn new(key: &Key<Self>) -> Self {
let key_bytes = key.as_slice();
let key1_len = key_bytes.len() - 32;
let key1 = &key_bytes[..key1_len];
let key2 = Block::<C>::try_from(&key_bytes[key1_len..key1_len + 16])
.unwrap_or_else(|_| unreachable!());
let key3 =
Block::<C>::try_from(&key_bytes[key1_len + 16..]).unwrap_or_else(|_| unreachable!());
let cipher = C::new_from_slice(key1).unwrap_or_else(|_| unreachable!());
let mut mode = Self {
cipher,
key2,
key3,
tweak: Block::<C>::default(),
};
mode.tweak = mode.hash_ad(&[]);
mode
}
}
impl<C> IvSizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type IvSize = U16;
}
impl<C> KeyIvInit for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeyInit,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
#[inline]
fn new(key: &Key<Self>, iv: &Iv<Self>) -> Self {
let mut mode = <Self as KeyInit>::new(key);
mode.tweak = mode.hash_ad(iv.as_slice());
mode
}
}
impl<C> cipher::AlgorithmName for Eme2<C>
where
C: BlockCipherEncrypt
+ BlockCipherDecrypt
+ BlockSizeUser<BlockSize = U16>
+ KeySizeUser
+ cipher::AlgorithmName,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Eme2<")?;
<C as cipher::AlgorithmName>::write_alg_name(f)?;
f.write_str(">")
}
}
impl<C> fmt::Debug for Eme2<C>
where
C: BlockCipherEncrypt
+ BlockCipherDecrypt
+ BlockSizeUser<BlockSize = U16>
+ KeySizeUser
+ cipher::AlgorithmName,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Eme2<")?;
<C as cipher::AlgorithmName>::write_alg_name(f)?;
f.write_str("> { ... }")
}
}
impl<C> Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
pub fn hash_ad(&self, ad: &[u8]) -> Block<C> {
let mut t_star = [0u8; BLOCK_SIZE];
if ad.is_empty() {
t_star.copy_from_slice(self.key3.as_slice());
encrypt_block(&self.cipher, &mut t_star);
return t_star.into();
}
let mut current_key3 = [0u8; BLOCK_SIZE];
current_key3.copy_from_slice(self.key3.as_slice());
let mut tt = [0u8; BLOCK_SIZE];
let chunks = ad.chunks(BLOCK_SIZE);
let r = chunks.len();
current_key3 = mult_by_two(¤t_key3);
for (i, chunk) in chunks.enumerate() {
let is_last = i == r - 1;
let mut block = [0u8; BLOCK_SIZE];
if is_last {
if chunk.len() < BLOCK_SIZE {
block[..chunk.len()].copy_from_slice(chunk);
block[chunk.len()] = 0x80;
current_key3 = mult_by_two(¤t_key3);
} else {
block.copy_from_slice(chunk);
}
} else {
block.copy_from_slice(chunk);
}
xor_into(&mut block, ¤t_key3);
encrypt_block(&self.cipher, &mut block);
xor_into(&mut block, ¤t_key3);
xor_into(&mut tt, &block);
if !is_last {
current_key3 = mult_by_two(¤t_key3);
}
}
#[cfg(feature = "zeroize")]
{
current_key3.zeroize();
}
tt.into()
}
pub const fn t_star(&self) -> &Block<C> {
&self.tweak
}
pub const fn set_t_star(&mut self, t_star: Block<C>) {
self.tweak = t_star;
}
pub fn encrypt(&self, data: &mut [u8]) -> Result<(), Error> {
let tweak_arr = block_to_array::<C>(&self.tweak);
self.encrypt_core(&tweak_arr, data)
}
pub fn decrypt(&self, data: &mut [u8]) -> Result<(), Error> {
let tweak_arr = block_to_array::<C>(&self.tweak);
self.decrypt_core(&tweak_arr, data)
}
pub fn encrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
#[cfg_attr(not(feature = "zeroize"), allow(unused_mut))]
let mut t_star = self.hash_ad(associated_data);
#[cfg_attr(not(feature = "zeroize"), allow(unused_mut))]
let mut tweak_arr = block_to_array::<C>(&t_star);
let res = self.encrypt_core(&tweak_arr, data);
#[cfg(feature = "zeroize")]
{
t_star.zeroize();
tweak_arr.zeroize();
}
res
}
pub fn decrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
#[cfg_attr(not(feature = "zeroize"), allow(unused_mut))]
let mut t_star = self.hash_ad(associated_data);
#[cfg_attr(not(feature = "zeroize"), allow(unused_mut))]
let mut tweak_arr = block_to_array::<C>(&t_star);
let res = self.decrypt_core(&tweak_arr, data);
#[cfg(feature = "zeroize")]
{
t_star.zeroize();
tweak_arr.zeroize();
}
res
}
fn encrypt_core(&self, tweak_slice: &[u8; 16], data: &mut [u8]) -> Result<(), Error> {
let len = data.len();
if len < BLOCK_SIZE {
return Err(Error::DataTooShort);
}
let m = len.div_ceil(BLOCK_SIZE);
let last_full = if len.is_multiple_of(BLOCK_SIZE) {
m
} else {
m - 1
};
let (mask_cipher_first, mask_delta_first, ccc_m, c_m) =
self.encrypt_pass1_and_mix(tweak_slice, data, len, m, last_full);
self.encrypt_pass2_and_3(
tweak_slice,
data,
len,
m,
last_full,
mask_cipher_first,
mask_delta_first,
ccc_m,
c_m,
);
Ok(())
}
fn encrypt_pass1_and_mix(
&self,
tweak_slice: &[u8; 16],
data: &mut [u8],
len: usize,
m: usize,
last_full: usize,
) -> (
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
) {
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut block, &l_current);
encrypt_block(&self.cipher, &mut block);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&block);
l_current = mult_by_two(&l_current);
}
let mut ppp_m = [0u8; BLOCK_SIZE];
if last_full < m {
let rem = len % BLOCK_SIZE;
ppp_m[..rem].copy_from_slice(&data[last_full * BLOCK_SIZE..len]);
ppp_m[rem] = 0x80;
}
let mut sp = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sp, &ppp_i);
}
if last_full < m {
xor_into(&mut sp, &ppp_m);
}
let mut ppp_0 = [0u8; BLOCK_SIZE];
ppp_0.copy_from_slice(&data[0..BLOCK_SIZE]);
let mut mask_plain_first = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_plain_first, &ppp_0, &sp);
xor_into(&mut mask_plain_first, tweak_slice);
let mut mask_cipher_first;
let mut ccc_m = [0u8; BLOCK_SIZE];
let mut c_m = [0u8; BLOCK_SIZE];
let mut mm = [0u8; BLOCK_SIZE];
if last_full < m {
mm.copy_from_slice(&mask_plain_first);
encrypt_block(&self.cipher, &mut mm);
mask_cipher_first = mm;
encrypt_block(&self.cipher, &mut mask_cipher_first);
let rem = len % BLOCK_SIZE;
for i in 0..rem {
c_m[i] = data[last_full * BLOCK_SIZE + i] ^ mm[i];
}
ccc_m[..rem].copy_from_slice(&c_m[..rem]);
ccc_m[rem] = 0x80;
} else {
mask_cipher_first = mask_plain_first;
encrypt_block(&self.cipher, &mut mask_cipher_first);
}
let mut mask_delta_first = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_delta_first, &mask_plain_first, &mask_cipher_first);
#[cfg(feature = "zeroize")]
{
l_current.zeroize();
ppp_m.zeroize();
sp.zeroize();
ppp_0.zeroize();
mask_plain_first.zeroize();
mm.zeroize();
}
(mask_cipher_first, mask_delta_first, ccc_m, c_m)
}
#[allow(clippy::too_many_arguments)]
fn encrypt_pass2_and_3(
&self,
tweak_slice: &[u8; 16],
data: &mut [u8],
len: usize,
m: usize,
last_full: usize,
mask_cipher_first: [u8; BLOCK_SIZE],
mask_delta_first: [u8; BLOCK_SIZE],
ccc_m: [u8; BLOCK_SIZE],
c_m: [u8; BLOCK_SIZE],
) {
let mut current_m_j = mask_delta_first;
let mut current_m_k = mask_delta_first;
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
let mut ccc_i = [0u8; BLOCK_SIZE];
let k = i & 127;
if k == 0 {
let mut mask_plain_block = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_plain_block, &ppp_i, &mask_delta_first);
let mut mask_cipher_block = mask_plain_block;
encrypt_block(&self.cipher, &mut mask_cipher_block);
xor_blocks(&mut current_m_j, &mask_plain_block, &mask_cipher_block);
xor_blocks(&mut ccc_i, &mask_cipher_block, &mask_delta_first);
current_m_k = current_m_j;
#[cfg(feature = "zeroize")]
{
mask_plain_block.zeroize();
mask_cipher_block.zeroize();
}
} else {
current_m_k = mult_by_two(¤t_m_k);
xor_blocks(&mut ccc_i, &ppp_i, ¤t_m_k);
}
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&ccc_i);
}
let mut sc = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sc, &ccc_i);
}
if last_full < m {
xor_into(&mut sc, &ccc_m);
}
let mut ccc_0 = [0u8; BLOCK_SIZE];
xor_blocks(&mut ccc_0, &mask_cipher_first, &sc);
xor_into(&mut ccc_0, tweak_slice);
data[0..BLOCK_SIZE].copy_from_slice(&ccc_0);
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut cc_i = [0u8; BLOCK_SIZE];
cc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
encrypt_block(&self.cipher, &mut cc_i);
xor_into(&mut cc_i, &l_current);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&cc_i);
l_current = mult_by_two(&l_current);
}
if last_full < m {
let rem = len % BLOCK_SIZE;
data[last_full * BLOCK_SIZE..len].copy_from_slice(&c_m[..rem]);
}
#[cfg(feature = "zeroize")]
{
let mut mask_cipher_first = mask_cipher_first;
let mut mask_delta_first = mask_delta_first;
let mut ccc_m = ccc_m;
let mut c_m = c_m;
mask_cipher_first.zeroize();
ccc_m.zeroize();
c_m.zeroize();
mask_delta_first.zeroize();
current_m_j.zeroize();
current_m_k.zeroize();
sc.zeroize();
ccc_0.zeroize();
l_current.zeroize();
}
}
fn decrypt_core(&self, tweak_slice: &[u8; 16], data: &mut [u8]) -> Result<(), Error> {
let len = data.len();
if len < BLOCK_SIZE {
return Err(Error::DataTooShort);
}
let m = len.div_ceil(BLOCK_SIZE);
let last_full = if len.is_multiple_of(BLOCK_SIZE) {
m
} else {
m - 1
};
let (mask_plain_first, mask_delta_first, ppp_m, p_m) =
self.decrypt_pass1_and_mix(tweak_slice, data, len, m, last_full);
self.decrypt_pass2_and_3(
tweak_slice,
data,
len,
m,
last_full,
mask_plain_first,
mask_delta_first,
ppp_m,
p_m,
);
Ok(())
}
fn decrypt_pass1_and_mix(
&self,
tweak_slice: &[u8; 16],
data: &mut [u8],
len: usize,
m: usize,
last_full: usize,
) -> (
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
[u8; BLOCK_SIZE],
) {
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut block, &l_current);
decrypt_block(&self.cipher, &mut block);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&block);
l_current = mult_by_two(&l_current);
}
let mut ccc_m = [0u8; BLOCK_SIZE];
if last_full < m {
let rem = len % BLOCK_SIZE;
ccc_m[..rem].copy_from_slice(&data[last_full * BLOCK_SIZE..len]);
ccc_m[rem] = 0x80;
}
let mut sc = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sc, &ccc_i);
}
if last_full < m {
xor_into(&mut sc, &ccc_m);
}
let mut ccc_0 = [0u8; BLOCK_SIZE];
ccc_0.copy_from_slice(&data[0..BLOCK_SIZE]);
let mut mask_cipher_first = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_cipher_first, &ccc_0, &sc);
xor_into(&mut mask_cipher_first, tweak_slice);
let mut mask_plain_first;
let mut ppp_m = [0u8; BLOCK_SIZE];
let mut p_m = [0u8; BLOCK_SIZE];
let mut mm = [0u8; BLOCK_SIZE];
if last_full < m {
mm.copy_from_slice(&mask_cipher_first);
decrypt_block(&self.cipher, &mut mm);
mask_plain_first = mm;
decrypt_block(&self.cipher, &mut mask_plain_first);
let rem = len % BLOCK_SIZE;
for i in 0..rem {
p_m[i] = data[last_full * BLOCK_SIZE + i] ^ mm[i];
}
ppp_m[..rem].copy_from_slice(&p_m[..rem]);
ppp_m[rem] = 0x80;
} else {
mask_plain_first = mask_cipher_first;
decrypt_block(&self.cipher, &mut mask_plain_first);
}
let mut mask_delta_first = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_delta_first, &mask_plain_first, &mask_cipher_first);
#[cfg(feature = "zeroize")]
{
l_current.zeroize();
ccc_m.zeroize();
sc.zeroize();
ccc_0.zeroize();
mask_cipher_first.zeroize();
mm.zeroize();
}
(mask_plain_first, mask_delta_first, ppp_m, p_m)
}
#[allow(clippy::too_many_arguments)]
fn decrypt_pass2_and_3(
&self,
tweak_slice: &[u8; 16],
data: &mut [u8],
len: usize,
m: usize,
last_full: usize,
mask_plain_first: [u8; BLOCK_SIZE],
mask_delta_first: [u8; BLOCK_SIZE],
ppp_m: [u8; BLOCK_SIZE],
p_m: [u8; BLOCK_SIZE],
) {
let mut current_m_j = mask_delta_first;
let mut current_m_k = mask_delta_first;
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
let mut ppp_i = [0u8; BLOCK_SIZE];
let k = i & 127;
if k == 0 {
let mut mask_cipher_block = [0u8; BLOCK_SIZE];
xor_blocks(&mut mask_cipher_block, &ccc_i, &mask_delta_first);
let mut mask_plain_block = mask_cipher_block;
decrypt_block(&self.cipher, &mut mask_plain_block);
xor_blocks(&mut current_m_j, &mask_plain_block, &mask_cipher_block);
xor_blocks(&mut ppp_i, &mask_plain_block, &mask_delta_first);
current_m_k = current_m_j;
#[cfg(feature = "zeroize")]
{
mask_cipher_block.zeroize();
mask_plain_block.zeroize();
}
} else {
current_m_k = mult_by_two(¤t_m_k);
xor_blocks(&mut ppp_i, &ccc_i, ¤t_m_k);
}
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&ppp_i);
}
let mut sp = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sp, &ppp_i);
}
if last_full < m {
xor_into(&mut sp, &ppp_m);
}
let mut ppp_0 = [0u8; BLOCK_SIZE];
xor_blocks(&mut ppp_0, &mask_plain_first, &sp);
xor_into(&mut ppp_0, tweak_slice);
data[0..BLOCK_SIZE].copy_from_slice(&ppp_0);
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut pp_i = [0u8; BLOCK_SIZE];
pp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
decrypt_block(&self.cipher, &mut pp_i);
xor_into(&mut pp_i, &l_current);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&pp_i);
l_current = mult_by_two(&l_current);
}
if last_full < m {
let rem = len % BLOCK_SIZE;
data[last_full * BLOCK_SIZE..len].copy_from_slice(&p_m[..rem]);
}
#[cfg(feature = "zeroize")]
{
let mut mask_plain_first = mask_plain_first;
let mut mask_delta_first = mask_delta_first;
let mut ppp_m = ppp_m;
let mut p_m = p_m;
mask_plain_first.zeroize();
ppp_m.zeroize();
p_m.zeroize();
mask_delta_first.zeroize();
current_m_j.zeroize();
current_m_k.zeroize();
sp.zeroize();
ppp_0.zeroize();
l_current.zeroize();
}
}
}