#[cfg(not(feature = "elgamal3"))]
use crate::arithmetic::group_elements::GroupElement;
use crate::arithmetic::group_elements::G;
use crate::arithmetic::scalars::ScalarNonZero;
use crate::core::elgamal::*;
#[cfg(feature = "elgamal3")]
pub fn rerandomize(encrypted: &ElGamal, r: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: r * G + encrypted.gb,
gc: r * encrypted.gy + encrypted.gc,
gy: encrypted.gy,
}
}
#[cfg(not(feature = "elgamal3"))]
pub fn rerandomize(encrypted: &ElGamal, gy: &GroupElement, r: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: r * G + encrypted.gb,
gc: r * gy + encrypted.gc,
}
}
pub fn reshuffle(encrypted: &ElGamal, s: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: s * encrypted.gb,
gc: s * encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: encrypted.gy,
}
}
pub fn rekey(encrypted: &ElGamal, k: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: k.invert() * encrypted.gb, gc: encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: k * encrypted.gy,
}
}
pub fn rsk(encrypted: &ElGamal, s: &ScalarNonZero, k: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: (s * k.invert()) * encrypted.gb, gc: s * encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: k * encrypted.gy,
}
}
#[cfg(feature = "elgamal3")]
pub fn rrsk(m: &ElGamal, r: &ScalarNonZero, s: &ScalarNonZero, k: &ScalarNonZero) -> ElGamal {
let ski = s * k.invert();
ElGamal {
gb: ski * m.gb + ski * r * G,
gc: (s * r) * m.gy + s * m.gc,
gy: k * m.gy,
}
}
#[cfg(not(feature = "elgamal3"))]
pub fn rrsk(
m: &ElGamal,
gy: &GroupElement,
r: &ScalarNonZero,
s: &ScalarNonZero,
k: &ScalarNonZero,
) -> ElGamal {
let ski = s * k.invert();
ElGamal {
gb: ski * m.gb + ski * r * G,
gc: (s * r) * gy + s * m.gc,
}
}
pub fn reshuffle2(m: &ElGamal, s_from: &ScalarNonZero, s_to: &ScalarNonZero) -> ElGamal {
let s = s_from.invert() * s_to;
reshuffle(m, &s)
}
pub fn rekey2(m: &ElGamal, k_from: &ScalarNonZero, k_to: &ScalarNonZero) -> ElGamal {
let k = k_from.invert() * k_to;
rekey(m, &k)
}
pub fn rsk2(
m: &ElGamal,
s_from: &ScalarNonZero,
s_to: &ScalarNonZero,
k_from: &ScalarNonZero,
k_to: &ScalarNonZero,
) -> ElGamal {
let s = s_from.invert() * s_to;
let k = k_from.invert() * k_to;
rsk(m, &s, &k)
}
#[cfg(feature = "elgamal3")]
pub fn rrsk2(
m: &ElGamal,
r: &ScalarNonZero,
s_from: &ScalarNonZero,
s_to: &ScalarNonZero,
k_from: &ScalarNonZero,
k_to: &ScalarNonZero,
) -> ElGamal {
let s = s_from.invert() * s_to;
let k = k_from.invert() * k_to;
rrsk(m, r, &s, &k)
}
#[cfg(not(feature = "elgamal3"))]
pub fn rrsk2(
m: &ElGamal,
gy: &GroupElement,
r: &ScalarNonZero,
s_from: &ScalarNonZero,
s_to: &ScalarNonZero,
k_from: &ScalarNonZero,
k_to: &ScalarNonZero,
) -> ElGamal {
let s = s_from.invert() * s_to;
let k = k_from.invert() * k_to;
rrsk(m, gy, r, &s, &k)
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
use crate::arithmetic::group_elements::GroupElement;
use crate::core::elgamal::{decrypt, encrypt};
#[test]
fn rekey() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let k = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &gy, &mut rng);
let rekeyed = super::rekey(&encrypted, &k);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rekeyed, &(k * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rekeyed, &(k * y));
assert_eq!(m, decrypted);
}
#[test]
fn reshuffle() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &gy, &mut rng);
let reshuffled = super::reshuffle(&encrypted, &s);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&reshuffled, &y).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&reshuffled, &y);
assert_eq!(s * m, decrypted);
}
#[test]
fn rsk() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s = ScalarNonZero::random(&mut rng);
let k = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &gy, &mut rng);
let rsked = super::rsk(&encrypted, &s, &k);
assert_eq!(rsked, super::rekey(&super::reshuffle(&encrypted, &s), &k));
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rsked, &(k * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rsked, &(k * y));
assert_eq!(s * m, decrypted);
}
#[test]
fn rrsk() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let r = ScalarNonZero::random(&mut rng);
let s = ScalarNonZero::random(&mut rng);
let k = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &gy, &mut rng);
#[cfg(feature = "elgamal3")]
let rrsked = super::rrsk(&encrypted, &r, &s, &k);
#[cfg(not(feature = "elgamal3"))]
let rrsked = super::rrsk(&encrypted, &gy, &r, &s, &k);
#[cfg(feature = "elgamal3")]
assert_eq!(
rrsked,
super::rekey(&super::reshuffle(&rerandomize(&encrypted, &r), &s), &k)
);
#[cfg(not(feature = "elgamal3"))]
assert_eq!(
rrsked,
super::rekey(&super::reshuffle(&rerandomize(&encrypted, &gy, &r), &s), &k)
);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rrsked, &(k * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rrsked, &(k * y));
assert_eq!(s * m, decrypted);
}
#[test]
fn rekey2_from_to() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let k_from = ScalarNonZero::random(&mut rng);
let k_to = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &(k_from * gy), &mut rng);
let rekeyed = rekey2(&encrypted, &k_from, &k_to);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rekeyed, &(k_to * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rekeyed, &(k_to * y));
assert_eq!(m, decrypted);
}
#[test]
fn reshuffle2_from_to() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s_from = ScalarNonZero::random(&mut rng);
let s_to = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &gy, &mut rng);
let reshuffled = reshuffle2(&encrypted, &s_from, &s_to);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&reshuffled, &y).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&reshuffled, &y);
assert_eq!(s_from.invert() * s_to * m, decrypted);
}
#[test]
fn rsk2_from_to() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s_from = ScalarNonZero::random(&mut rng);
let s_to = ScalarNonZero::random(&mut rng);
let k_from = ScalarNonZero::random(&mut rng);
let k_to = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&m, &(k_from * gy), &mut rng);
let rsked = rsk2(&encrypted, &s_from, &s_to, &k_from, &k_to);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rsked, &(k_to * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rsked, &(k_to * y));
assert_eq!(s_from.invert() * s_to * m, decrypted);
}
#[test]
fn commutativity() {
let mut rng = rand::rng();
let sk = ScalarNonZero::random(&mut rng);
let pk = sk * G;
let sj = ScalarNonZero::random(&mut rng);
let yj = sj * sk;
assert_eq!(yj * G, sj * pk);
let value = GroupElement::random(&mut rng);
let encrypted = encrypt(&value, &pk, &mut rng);
let k = ScalarNonZero::random(&mut rng);
let n = ScalarNonZero::random(&mut rng);
assert_eq!(
super::reshuffle(&super::rekey(&encrypted, &k), &n),
super::rekey(&super::reshuffle(&encrypted, &n), &k)
);
assert_eq!(
super::reshuffle(&super::rekey(&encrypted, &k), &n),
super::rsk(&encrypted, &n, &k)
);
}
#[test]
fn reshuffle2_transitivity() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s_user1 = ScalarNonZero::random(&mut rng);
let s_user2 = ScalarNonZero::random(&mut rng);
let s_user3 = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&(s_user1 * m), &gy, &mut rng);
let reshuffled_1_to_2 = reshuffle2(&encrypted, &s_user1, &s_user2);
let reshuffled_2_to_3 = reshuffle2(&reshuffled_1_to_2, &s_user2, &s_user3);
let reshuffled_1_to_3 = reshuffle2(&encrypted, &s_user1, &s_user3);
assert_eq!(reshuffled_2_to_3, reshuffled_1_to_3);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&reshuffled_1_to_3, &y).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&reshuffled_1_to_3, &y);
assert_eq!(s_user3 * m, decrypted);
}
#[test]
fn rsk2_transitivity() {
let mut rng = rand::rng();
let y = ScalarNonZero::random(&mut rng);
let gy = y * G;
let s_user1 = ScalarNonZero::random(&mut rng);
let s_user2 = ScalarNonZero::random(&mut rng);
let s_user3 = ScalarNonZero::random(&mut rng);
let k_user1 = ScalarNonZero::random(&mut rng);
let k_user2 = ScalarNonZero::random(&mut rng);
let k_user3 = ScalarNonZero::random(&mut rng);
let m = GroupElement::random(&mut rng);
let encrypted = encrypt(&(s_user1 * m), &(k_user1 * gy), &mut rng);
let rsked_1_to_2 = rsk2(&encrypted, &s_user1, &s_user2, &k_user1, &k_user2);
let rsked_2_to_3 = rsk2(&rsked_1_to_2, &s_user2, &s_user3, &k_user2, &k_user3);
let rsked_1_to_3 = rsk2(&encrypted, &s_user1, &s_user3, &k_user1, &k_user3);
assert_eq!(rsked_2_to_3, rsked_1_to_3);
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&rsked_1_to_3, &(k_user3 * y)).expect("decryption should succeed");
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&rsked_1_to_3, &(k_user3 * y));
assert_eq!(s_user3 * m, decrypted);
}
}