use crate::{
core::actually_used_field::ActuallyUsedField,
traits::{
FromF25519,
GetSharedRescueKey,
MxeRescueKey,
MxeX25519PrivateKey,
Reveal,
ToMontgomery,
},
utils::{
crypto::{
key::{RescueKey, X25519PrivateKey, X25519PublicKey},
rescue_desc::{RescueArg, RescueDesc},
},
curve_point::Curve,
elliptic_curve::F25519,
matrix::Matrix,
},
};
use std::ops::Mul;
#[allow(dead_code)]
pub struct RescueCipher<F: ActuallyUsedField, T: RescueArg<F>> {
desc: RescueDesc<F, T>,
}
impl<F: ActuallyUsedField, T: RescueArg<F>> RescueCipher<F, T> {
pub fn new(key: RescueKey<T>) -> Self {
RescueCipher {
desc: RescueDesc::new_cipher_desc(Matrix::from(key)),
}
}
pub fn new_with_client<
Base: F25519,
S: Clone + Copy + MxeX25519PrivateKey + Mul<C, Output = C>,
C: Curve + ToMontgomery<Output = Base>,
>(
pubkey: X25519PublicKey<C>,
) -> Self
where
T: FromF25519<Base> + GetSharedRescueKey<C>,
{
Self::new(RescueKey::new_with_client::<Base, S, C>(pubkey))
}
pub fn new_with_client_from_keys<
Base: F25519,
S: Clone + Copy + Mul<C, Output = C>,
C: Curve + ToMontgomery<Output = Base>,
>(
private_key: X25519PrivateKey<S>,
client_pubkey: X25519PublicKey<C>,
) -> Self
where
T: FromF25519<Base>,
{
Self::new(RescueKey::new_with_client_from_keys::<F, Base, S, C>(
private_key,
client_pubkey,
))
}
pub fn new_for_mxe() -> Self
where
T: MxeRescueKey,
{
Self::new(RescueKey::<T>::mxe_rescue_key())
}
fn get_counter(nonce: T, n_blocks: usize) -> Vec<T> {
(0..n_blocks).fold(Vec::new(), |mut acc, i| {
acc.extend([
nonce,
T::from(F::from(i as u64)),
T::from(F::ZERO),
T::from(F::ZERO),
T::from(F::ZERO),
]);
acc
})
}
fn encrypt_batch(desc: &RescueDesc<F, T>, ptxt: &[T], counter: &[T], output: &mut Vec<T>)
where
T: Reveal,
{
let n_ptxt = ptxt.len();
let encrypted_counter = desc.permute(&Matrix::from(counter.to_vec()));
output.extend(
(Matrix::from(ptxt)
+ Matrix::from(
encrypted_counter
.into_iter()
.take(n_ptxt)
.collect::<Vec<T>>(),
))
.into_iter()
.map(|c| c.reveal()),
)
}
pub fn encrypt(&self, masked_plaintext: Vec<T>, nonce: T) -> Vec<T>
where
T: Reveal,
{
let plaintext = masked_plaintext;
let n_blocks = plaintext.len().div_ceil(self.desc.m);
let counter = RescueCipher::get_counter(nonce, n_blocks);
let mut result = Vec::new();
for i in 0..n_blocks {
let cnt = self.desc.m * i;
Self::encrypt_batch(
&self.desc,
&plaintext[cnt..(cnt + self.desc.m).min(plaintext.len())],
&counter[cnt..cnt + self.desc.m],
&mut result,
)
}
result
}
fn decrypt_batch(desc: &RescueDesc<F, T>, ctxt: &[T], counter: &[T], output: &mut Vec<T>) {
let n_ctxt = ctxt.len();
let encrypted_counter = desc.permute(&Matrix::from(counter.to_vec()));
output.extend(
Matrix::from(ctxt)
- Matrix::from(
encrypted_counter
.into_iter()
.take(n_ctxt)
.collect::<Vec<T>>(),
),
)
}
pub fn decrypt(&self, ciphertext: Vec<T>, nonce: T) -> Vec<T> {
let n_blocks = ciphertext.len().div_ceil(self.desc.m);
let counter = RescueCipher::get_counter(nonce, n_blocks);
let mut decrypted = Vec::new();
for i in 0..n_blocks {
let cnt = self.desc.m * i;
Self::decrypt_batch(
&self.desc,
&ciphertext[cnt..(cnt + self.desc.m).min(ciphertext.len())],
&counter[cnt..cnt + self.desc.m],
&mut decrypted,
);
}
decrypted
}
}