libpep/low_level/primitives.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! PEP primitives for [rekey]ing, [reshuffle]ing, [rerandomize]ation of [ElGamal] ciphertexts, their
//! transitive and reversible n-PEP extensions, and combined versions.
use crate::internal::arithmetic::*;
use crate::low_level::elgamal::*;
/// Change the representation of a ciphertext without changing the contents.
/// Used to make multiple unlinkable copies of the same ciphertext (when disclosing a single
/// stored message multiple times).
#[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,
}
}
/// Change the representation of a ciphertext without changing the contents.
/// Used to make multiple unlinkable copies of the same ciphertext (when disclosing a single
/// stored message multiple times).
/// Requires the public key `gy` that was used to encrypt the message to be provided.
#[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,
}
}
/// Change the contents of a ciphertext with factor `s`, i.e. message `M` becomes `s * M`.
/// Can be used to blindly and pseudo-randomly pseudonymize identifiers.
pub fn reshuffle(encrypted: &ElGamal, s: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: s * encrypted.gb,
gc: s * encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: encrypted.gy,
}
}
/// Make a message encrypted under one key decryptable under another key.
/// If the original message was encrypted under key `Y`, the new message will be encrypted under key
/// `k * Y` such that users with secret key `k * y` can decrypt it.
pub fn rekey(encrypted: &ElGamal, k: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: k.invert() * encrypted.gb, // TODO k.invert can be precomputed
gc: encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: k * encrypted.gy,
}
}
/// Combination of [`reshuffle`] and [`rekey`] (more efficient and secure than applying them
/// separately).
pub fn rsk(encrypted: &ElGamal, s: &ScalarNonZero, k: &ScalarNonZero) -> ElGamal {
ElGamal {
gb: (s * k.invert()) * encrypted.gb, // TODO s * k.invert can be precomputed
gc: s * encrypted.gc,
#[cfg(feature = "elgamal3")]
gy: k * encrypted.gy,
}
}
/// Combination of [`rerandomize`], [`reshuffle`] and [`rekey`] (more efficient and secure than
/// applying them separately).
#[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,
}
}
/// Combination of [`rerandomize`], [`reshuffle`] and [`rekey`] (more efficient and secure than
/// applying them separately).
#[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,
}
}
/// A transitive and reversible n-PEP extension of [`reshuffle`], reshuffling from one pseudonym to
/// another.
pub fn reshuffle2(m: &ElGamal, s_from: &ScalarNonZero, s_to: &ScalarNonZero) -> ElGamal {
let s = s_from.invert() * s_to;
reshuffle(m, &s)
}
/// A transitive and reversible n-PEP extension of [`rekey`], rekeying from one key to
/// another.
pub fn rekey2(m: &ElGamal, k_from: &ScalarNonZero, k_to: &ScalarNonZero) -> ElGamal {
let k = k_from.invert() * k_to;
rekey(m, &k)
}
/// A transitive and reversible n-PEP extension of [`rsk`].
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)
}
/// A transitive and reversible n-PEP extension of [`rrsk`].
#[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)
}
/// A transitive and reversible n-PEP extension of [`rrsk`].
#[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)
}