use std::ops::{Add, Mul, Sub};
use crate::cryptosystems::{Associable, AssociatedCiphertext, EncryptionKey};
auto trait PotentialInput {}
impl<'pk, C, PK> !PotentialInput for AssociatedCiphertext<'pk, C, PK> {}
pub trait HomomorphicAddition: EncryptionKey {
fn add(
&self,
ciphertext_a: &Self::Ciphertext,
ciphertext_b: &Self::Ciphertext,
) -> Self::Ciphertext;
fn sub(
&self,
ciphertext_a: &Self::Ciphertext,
ciphertext_b: &Self::Ciphertext,
) -> Self::Ciphertext;
fn mul_constant(&self, ciphertext: &Self::Ciphertext, input: &Self::Input) -> Self::Ciphertext;
fn add_constant(
&self,
ciphertext: &Self::Ciphertext,
constant: &Self::Plaintext,
) -> Self::Ciphertext;
fn sub_constant(
&self,
ciphertext: &Self::Ciphertext,
constant: &Self::Plaintext,
) -> Self::Ciphertext;
}
impl<'pk, C: Associable<PK>, PK: EncryptionKey<Ciphertext = C> + HomomorphicAddition> Add
for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn add(self, rhs: Self) -> Self::Output {
debug_assert_eq!(self.public_key, rhs.public_key);
self.public_key
.add(&self.ciphertext, &rhs.ciphertext)
.associate(self.public_key)
}
}
impl<
'pk,
P: PotentialInput,
C: Associable<PK>,
PK: EncryptionKey<Ciphertext = C, Plaintext = P> + HomomorphicAddition,
> Add<&P> for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn add(self, rhs: &PK::Plaintext) -> Self::Output {
self.public_key
.add_constant(&self.ciphertext, rhs)
.associate(self.public_key)
}
}
impl<'pk, C: Associable<PK>, PK: EncryptionKey<Ciphertext = C> + HomomorphicAddition> Sub
for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn sub(self, rhs: Self) -> Self::Output {
debug_assert_eq!(self.public_key, rhs.public_key);
self.public_key
.sub(&self.ciphertext, &rhs.ciphertext)
.associate(self.public_key)
}
}
impl<
'pk,
P: PotentialInput,
C: Associable<PK>,
PK: EncryptionKey<Ciphertext = C, Plaintext = P> + HomomorphicAddition,
> Sub<&P> for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn sub(self, rhs: &PK::Plaintext) -> Self::Output {
self.public_key
.sub_constant(&self.ciphertext, rhs)
.associate(self.public_key)
}
}
impl<
'pk,
P: PotentialInput,
C: Associable<PK>,
PK: EncryptionKey<Input = P, Ciphertext = C> + HomomorphicAddition,
> Mul<&P> for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn mul(self, rhs: &PK::Input) -> Self::Output {
self.public_key
.mul_constant(&self.ciphertext, rhs)
.associate(self.public_key)
}
}
pub trait HomomorphicMultiplication: EncryptionKey {
fn mul(
&self,
ciphertext_a: &Self::Ciphertext,
ciphertext_b: &Self::Ciphertext,
) -> Self::Ciphertext;
fn pow(&self, ciphertext: &Self::Ciphertext, input: &Self::Input) -> Self::Ciphertext;
}
impl<'pk, C: Associable<PK>, PK: EncryptionKey<Ciphertext = C> + HomomorphicMultiplication> Mul
for &AssociatedCiphertext<'pk, C, PK>
{
type Output = AssociatedCiphertext<'pk, C, PK>;
fn mul(self, rhs: Self) -> Self::Output {
debug_assert_eq!(self.public_key, rhs.public_key);
self.public_key
.mul(&self.ciphertext, &rhs.ciphertext)
.associate(self.public_key)
}
}
impl<'pk, C: Associable<PK>, PK: EncryptionKey<Ciphertext = C> + HomomorphicMultiplication>
AssociatedCiphertext<'pk, C, PK>
{
pub fn pow(&self, rhs: &PK::Input) -> AssociatedCiphertext<'pk, C, PK> {
self.public_key
.pow(&self.ciphertext, rhs)
.associate(self.public_key)
}
}