use crate::{mod_in, Ciphertext, DecryptionKey, Nonce};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use unknown_order::BigNumber;
use zeroize::Zeroize;
#[derive(Clone, Debug, Zeroize)]
pub struct EncryptionKey {
pub(crate) n: BigNumber, pub(crate) nn: BigNumber, }
#[cfg(feature = "wasm")]
wasm_slice_impl!(EncryptionKey);
impl Serialize for EncryptionKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.n.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for EncryptionKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let n = BigNumber::deserialize(deserializer)?;
Ok(Self::from_n(n))
}
}
impl From<&DecryptionKey> for EncryptionKey {
fn from(sk: &DecryptionKey) -> EncryptionKey {
sk.pk.clone()
}
}
impl EncryptionKey {
pub(crate) fn l(&self, x: &BigNumber) -> Option<BigNumber> {
let one = BigNumber::one();
if x % &self.n != one {
return None;
}
if !mod_in(&x, &self.nn) {
return None;
}
Some((x - &one) / &self.n)
}
#[allow(clippy::many_single_char_names)]
pub fn encrypt<M>(&self, x: M, r: Option<Nonce>) -> Option<(Ciphertext, Nonce)>
where
M: AsRef<[u8]>,
{
let xx = BigNumber::from_slice(x);
if !mod_in(&xx, &self.n) {
return None;
}
let r = r.unwrap_or_else(|| Nonce::random(&self.n));
if !mod_in(&r, &self.n) {
return None;
}
let a = (&self.n + BigNumber::one()).modpow(&xx, &self.nn);
let b = &r.modpow(&self.n, &self.nn);
let c = a.modmul(&b, &self.nn);
Some((c, r))
}
pub fn add(&self, c1: &Ciphertext, c2: &Ciphertext) -> Option<Ciphertext> {
let c1_check = mod_in(&c1, &self.nn);
let c2_check = mod_in(&c2, &self.nn);
if !c1_check | !c2_check {
return None;
}
Some(c1.modmul(c2, &self.nn))
}
pub fn mul(&self, c: &Ciphertext, a: &BigNumber) -> Option<Ciphertext> {
let c1_check = mod_in(&c, &self.nn);
let c2_check = mod_in(&a, &self.n);
if !c1_check | !c2_check {
return None;
}
Some(c.modpow(a, &self.nn))
}
pub fn to_bytes(&self) -> Vec<u8> {
self.n.to_bytes()
}
pub fn from_bytes<B: AsRef<[u8]>>(data: B) -> Result<Self, String> {
let data = data.as_ref();
let n = BigNumber::from_slice(data);
Ok(Self::from_n(n))
}
pub fn from_n(n: BigNumber) -> Self {
Self { nn: &n * &n, n }
}
pub fn n(&self) -> &BigNumber {
&self.n
}
pub fn nn(&self) -> &BigNumber {
&self.nn
}
}