use std::marker::PhantomData;
use rand::RngCore;
use crate::algebra::Module;
use crate::ecc::group::Bls12381G1;
use crate::ecc::group::CyclicModule;
use crate::ecc::group::Point;
#[cfg(feature = "curve-ristretto255")]
use crate::ecc::group::Ristretto255;
use crate::ecc::group::Secp256k1;
use crate::ecc::group::Secp256r1;
pub mod impls;
pub type GroupCiphertext<Element> = Vec<(Element, Element)>;
pub type Secp256k1ElGamal = ElGamal<Point<Secp256k1>>;
pub type Secp256r1ElGamal = ElGamal<Point<Secp256r1>>;
pub type Bls12381G1ElGamal = ElGamal<Point<Bls12381G1>>;
#[cfg(feature = "curve-ristretto255")]
pub type Ristretto255ElGamal = ElGamal<Point<Ristretto255>>;
pub struct ElGamalPublicKey<Element: CyclicModule> {
element: Element,
}
pub struct ElGamalSecretKey<Element: CyclicModule> {
scalar: Element::Scalar,
}
pub struct ElGamalKeyPair<Element: CyclicModule> {
secret: ElGamalSecretKey<Element>,
public: ElGamalPublicKey<Element>,
}
pub struct ElGamal<Element>(PhantomData<Element>);
impl<Element> ElGamalPublicKey<Element>
where Element: CyclicModule
{
pub fn from_element(element: Element) -> Self {
Self { element }
}
pub fn as_element(&self) -> &Element {
&self.element
}
pub fn into_element(self) -> Element {
self.element
}
}
impl<Element> Clone for ElGamalPublicKey<Element>
where Element: CyclicModule + Clone
{
fn clone(&self) -> Self {
Self::from_element(self.element.clone())
}
}
impl<Element> ElGamalSecretKey<Element>
where Element: CyclicModule
{
pub fn from_scalar(scalar: Element::Scalar) -> Self {
Self { scalar }
}
pub fn as_scalar(&self) -> &Element::Scalar {
&self.scalar
}
pub fn into_scalar(self) -> Element::Scalar {
self.scalar
}
pub fn public_key(&self) -> ElGamalPublicKey<Element> {
ElGamalPublicKey::from_element(Element::generator_mul(&self.scalar))
}
}
impl<Element> Clone for ElGamalSecretKey<Element>
where
Element: CyclicModule,
Element::Scalar: Clone,
{
fn clone(&self) -> Self {
Self::from_scalar(self.scalar.clone())
}
}
impl<Element> ElGamalKeyPair<Element>
where Element: CyclicModule
{
pub fn public_key(&self) -> &ElGamalPublicKey<Element> {
&self.public
}
pub fn secret_key(&self) -> &ElGamalSecretKey<Element> {
&self.secret
}
}
impl<Element> ElGamalSecretKey<Element>
where Element: CyclicModule
{
pub fn random_with_rng(rng: &mut impl RngCore) -> Self {
Self::from_scalar(Element::random_scalar_with_rng(rng))
}
pub fn random() -> Self {
Self::from_scalar(Element::random_scalar())
}
}
impl<Element> ElGamalKeyPair<Element>
where Element: CyclicModule
{
pub fn random_with_rng(rng: &mut impl RngCore) -> Self {
let secret = ElGamalSecretKey::<Element>::random_with_rng(rng);
let public = secret.public_key();
Self { secret, public }
}
pub fn random() -> Self {
let secret = ElGamalSecretKey::<Element>::random();
let public = secret.public_key();
Self { secret, public }
}
}
impl<Element> ElGamal<Element>
where
Element: CyclicModule + Module<Element::Scalar> + Clone,
Element::Scalar: Clone,
{
pub fn decrypt(
ciphertext: &[(Element, Element)],
secret_key: &ElGamalSecretKey<Element>,
) -> Vec<Element> {
ciphertext
.iter()
.map(|(c1, c2)| {
let mask = c1.clone() * secret_key.as_scalar().clone();
c2.clone() - mask
})
.collect()
}
pub fn encrypt_block(
message_element: Element,
public_key: &ElGamalPublicKey<Element>,
ephemeral_scalar: Element::Scalar,
) -> (Element, Element) {
let c1 = Element::generator_mul(&ephemeral_scalar);
let mask = public_key.as_element().clone() * ephemeral_scalar;
let c2 = message_element + mask;
(c1, c2)
}
pub fn encrypt_with_rng<I>(
message: I,
public_key: &ElGamalPublicKey<Element>,
rng: &mut impl RngCore,
) -> GroupCiphertext<Element>
where
I: IntoIterator<Item = Element>,
{
message
.into_iter()
.map(|message_element| {
let ephemeral_scalar = Element::random_scalar_with_rng(rng);
Self::encrypt_block(message_element, public_key, ephemeral_scalar)
})
.collect()
}
pub fn encrypt<I>(
message: I,
public_key: &ElGamalPublicKey<Element>,
) -> GroupCiphertext<Element>
where
I: IntoIterator<Item = Element>,
{
message
.into_iter()
.map(|message_element| {
let ephemeral_scalar = Element::random_scalar();
Self::encrypt_block(message_element, public_key, ephemeral_scalar)
})
.collect()
}
}
#[cfg(test)]
mod test_elgamal;