libpep/high_level/
contexts.rs

1//! Specification of [PseudonymizationDomain]s and [EncryptionContext]s and transcryption between them.
2//! Based on a simple string representations, this module provides the necessary types to describe
3//! transcryption between different domains and sessions.
4
5use crate::high_level::secrets::{
6    make_attribute_rekey_factor, make_pseudonym_rekey_factor, make_pseudonymisation_factor,
7    EncryptionSecret, PseudonymizationSecret,
8};
9use crate::internal::arithmetic::ScalarNonZero;
10use derive_more::{Deref, From};
11use serde::{Deserialize, Serialize};
12
13/// Pseudonymization domains are used to describe the domain in which pseudonyms exist (typically,
14/// a user's role or usergroup).
15/// With the `legacy-pep-repo-compatible` feature enabled, pseudonymization domains also include
16/// an `audience_type` field, which is used to distinguish between different types of audiences.
17#[derive(Clone, Eq, Hash, PartialEq, Debug, Deref, Serialize, Deserialize)]
18#[cfg(feature = "legacy-pep-repo-compatible")]
19pub struct PseudonymizationDomain {
20    #[deref]
21    pub payload: String,
22    pub audience_type: u32,
23}
24/// Encryption contexts are used to describe the context in which ciphertexts exist (typically, a
25/// user's session).
26/// With the `legacy-pep-repo-compatible` feature enabled, encryption contexts also include
27/// an `audience_type` field, which is used to distinguish between different types of audiences.
28#[derive(Clone, Eq, Hash, PartialEq, Debug, Deref, Serialize, Deserialize)]
29#[cfg(feature = "legacy-pep-repo-compatible")]
30pub struct EncryptionContext {
31    #[deref]
32    pub payload: String,
33    pub audience_type: u32,
34}
35
36/// Pseudonymization domains are used to describe the domain in which pseudonyms exist (typically,
37/// a user's role or usergroup).
38#[derive(Clone, Eq, Hash, PartialEq, Debug, Deref, Serialize, Deserialize)]
39#[cfg(not(feature = "legacy-pep-repo-compatible"))]
40pub struct PseudonymizationDomain(pub String);
41/// Encryption contexts are used to describe the domain in which ciphertexts exist (typically, a
42/// user's session).
43#[derive(Clone, Eq, Hash, PartialEq, Debug, Deref, Serialize, Deserialize)]
44#[cfg(not(feature = "legacy-pep-repo-compatible"))]
45pub struct EncryptionContext(pub String);
46
47impl PseudonymizationDomain {
48    #[cfg(feature = "legacy-pep-repo-compatible")]
49    pub fn from(payload: &str) -> Self {
50        PseudonymizationDomain {
51            payload: payload.to_string(),
52            audience_type: 0,
53        }
54    }
55    #[cfg(not(feature = "legacy-pep-repo-compatible"))]
56    pub fn from(payload: &str) -> Self {
57        PseudonymizationDomain(payload.to_string())
58    }
59
60    #[cfg(feature = "legacy-pep-repo-compatible")]
61    pub fn from_audience(payload: &str, audience_type: u32) -> Self {
62        PseudonymizationDomain {
63            payload: payload.to_string(),
64            audience_type,
65        }
66    }
67}
68impl EncryptionContext {
69    #[cfg(feature = "legacy-pep-repo-compatible")]
70    pub fn from(payload: &str) -> Self {
71        EncryptionContext {
72            payload: payload.to_string(),
73            audience_type: 0,
74        }
75    }
76    #[cfg(not(feature = "legacy-pep-repo-compatible"))]
77    pub fn from(payload: &str) -> Self {
78        EncryptionContext(payload.to_string())
79    }
80
81    #[cfg(feature = "legacy-pep-repo-compatible")]
82    pub fn from_audience(payload: &str, audience_type: u32) -> Self {
83        EncryptionContext {
84            payload: payload.to_string(),
85            audience_type,
86        }
87    }
88}
89
90/// High-level type for the factor used to [`rerandomize`](crate::low_level::primitives::rerandomize) an [ElGamal](crate::low_level::elgamal::ElGamal) ciphertext.
91#[derive(Copy, Clone, Eq, PartialEq, Debug, From)]
92pub struct RerandomizeFactor(pub(crate) ScalarNonZero);
93/// High-level type for the factor used to [`reshuffle`](crate::low_level::primitives::reshuffle) an [ElGamal](crate::low_level::elgamal::ElGamal) ciphertext.
94#[derive(Copy, Clone, Eq, PartialEq, Debug, From)]
95pub struct ReshuffleFactor(pub ScalarNonZero);
96/// Trait for rekey factors that can be extracted to a scalar.
97pub trait RekeyFactor {
98    fn scalar(&self) -> ScalarNonZero;
99}
100
101/// High-level type for the factor used to [`rekey`](crate::low_level::primitives::rekey) an [ElGamal](crate::low_level::elgamal::ElGamal) ciphertext for pseudonyms.
102#[derive(Copy, Clone, Eq, PartialEq, Debug, From)]
103pub struct PseudonymRekeyFactor(pub(crate) ScalarNonZero);
104
105impl RekeyFactor for PseudonymRekeyFactor {
106    fn scalar(&self) -> ScalarNonZero {
107        self.0
108    }
109}
110
111/// High-level type for the factor used to [`rekey`](crate::low_level::primitives::rekey) an [ElGamal](crate::low_level::elgamal::ElGamal) ciphertext for attributes.
112#[derive(Copy, Clone, Eq, PartialEq, Debug, From)]
113pub struct AttributeRekeyFactor(pub(crate) ScalarNonZero);
114
115impl RekeyFactor for AttributeRekeyFactor {
116    fn scalar(&self) -> ScalarNonZero {
117        self.0
118    }
119}
120
121/// High-level type for the factors used to [`rsk`](crate::low_level::primitives::rsk) an [ElGamal](crate::low_level::elgamal::ElGamal) ciphertext for pseudonyms.
122/// Contains both the reshuffle factor (`s`) and the rekey factor (`k`).
123#[derive(Eq, PartialEq, Clone, Copy, Debug, From)]
124pub struct PseudonymRSKFactors {
125    /// Reshuffle factor - transforms pseudonyms between different domains
126    pub s: ReshuffleFactor,
127    /// Rekey factor - transforms pseudonyms between different sessions
128    pub k: PseudonymRekeyFactor,
129}
130
131/// The information required to perform n-PEP pseudonymization from one domain and session to another.
132/// The pseudonymization info consists of a reshuffle and rekey factor.
133/// For efficiency, we do not actually use the [`rsk2`](crate::low_level::primitives::rsk2) operation, but instead use the regular [`rsk`](crate::low_level::primitives::rsk) operation
134/// with precomputed reshuffle and rekey factors, which is equivalent but more efficient.
135pub type PseudonymizationInfo = PseudonymRSKFactors;
136
137/// The information required to perform n-PEP rekeying of pseudonyms from one session to another.
138/// For efficiency, we do not actually use the [`rekey2`](crate::low_level::primitives::rekey2) operation, but instead use the regular [`rekey`](crate::low_level::primitives::rekey) operation
139/// with a precomputed rekey factor, which is equivalent but more efficient.
140pub type PseudonymRekeyInfo = PseudonymRekeyFactor;
141
142/// The information required to perform n-PEP rekeying of attributes from one session to another.
143/// For efficiency, we do not actually use the [`rekey2`](crate::low_level::primitives::rekey2) operation, but instead use the regular [`rekey`](crate::low_level::primitives::rekey) operation
144/// with a precomputed rekey factor, which is equivalent but more efficient.
145pub type AttributeRekeyInfo = AttributeRekeyFactor;
146impl PseudonymizationInfo {
147    /// Compute the pseudonymization info given pseudonymization domains, sessions and secrets.
148    pub fn new(
149        domain_from: &PseudonymizationDomain,
150        domain_to: &PseudonymizationDomain,
151        session_from: Option<&EncryptionContext>,
152        session_to: Option<&EncryptionContext>,
153        pseudonymization_secret: &PseudonymizationSecret,
154        encryption_secret: &EncryptionSecret,
155    ) -> Self {
156        let s_from = make_pseudonymisation_factor(pseudonymization_secret, domain_from);
157        let s_to = make_pseudonymisation_factor(pseudonymization_secret, domain_to);
158        let reshuffle_factor = ReshuffleFactor::from(s_from.0.invert() * s_to.0);
159        let rekey_factor = PseudonymRekeyInfo::new(session_from, session_to, encryption_secret);
160        Self {
161            s: reshuffle_factor,
162            k: rekey_factor,
163        }
164    }
165
166    /// Reverse the pseudonymization info (i.e., switch the direction of the pseudonymization).
167    pub fn reverse(&self) -> Self {
168        Self {
169            s: ReshuffleFactor::from(self.s.0.invert()),
170            k: PseudonymRekeyFactor::from(self.k.0.invert()),
171        }
172    }
173}
174impl PseudonymRekeyInfo {
175    /// Compute the rekey info for pseudonyms given sessions and secrets.
176    pub fn new(
177        session_from: Option<&EncryptionContext>,
178        session_to: Option<&EncryptionContext>,
179        encryption_secret: &EncryptionSecret,
180    ) -> Self {
181        let k_from = session_from
182            .map(|ctx| make_pseudonym_rekey_factor(encryption_secret, ctx))
183            .unwrap_or_else(|| PseudonymRekeyFactor(ScalarNonZero::one()));
184
185        let k_to = session_to
186            .map(|ctx| make_pseudonym_rekey_factor(encryption_secret, ctx))
187            .unwrap_or_else(|| PseudonymRekeyFactor(ScalarNonZero::one()));
188
189        Self::from(k_from.0.invert() * k_to.0)
190    }
191
192    /// Reverse the rekey info (i.e., switch the direction of the rekeying).
193    pub fn reverse(&self) -> Self {
194        Self::from(self.0.invert())
195    }
196}
197
198impl AttributeRekeyInfo {
199    /// Compute the rekey info for attributes given sessions and secrets.
200    pub fn new(
201        session_from: Option<&EncryptionContext>,
202        session_to: Option<&EncryptionContext>,
203        encryption_secret: &EncryptionSecret,
204    ) -> Self {
205        let k_from = session_from
206            .map(|ctx| make_attribute_rekey_factor(encryption_secret, ctx))
207            .unwrap_or_else(|| AttributeRekeyFactor(ScalarNonZero::one()));
208
209        let k_to = session_to
210            .map(|ctx| make_attribute_rekey_factor(encryption_secret, ctx))
211            .unwrap_or_else(|| AttributeRekeyFactor(ScalarNonZero::one()));
212
213        Self::from(k_from.0.invert() * k_to.0)
214    }
215
216    /// Reverse the rekey info (i.e., switch the direction of the rekeying).
217    pub fn reverse(&self) -> Self {
218        Self::from(self.0.invert())
219    }
220}
221impl From<PseudonymizationInfo> for PseudonymRekeyInfo {
222    fn from(x: PseudonymizationInfo) -> Self {
223        x.k
224    }
225}
226
227/// The information required for transcryption, containing both pseudonymization info and attribute rekey info.
228#[derive(Eq, PartialEq, Clone, Copy, Debug)]
229pub struct TranscryptionInfo {
230    pub pseudonym: PseudonymizationInfo,
231    pub attribute: AttributeRekeyInfo,
232}
233
234impl TranscryptionInfo {
235    /// Compute the transcryption info given pseudonymization domains, sessions and secrets.
236    pub fn new(
237        domain_from: &PseudonymizationDomain,
238        domain_to: &PseudonymizationDomain,
239        session_from: Option<&EncryptionContext>,
240        session_to: Option<&EncryptionContext>,
241        pseudonymization_secret: &PseudonymizationSecret,
242        encryption_secret: &EncryptionSecret,
243    ) -> Self {
244        Self {
245            pseudonym: PseudonymizationInfo::new(
246                domain_from,
247                domain_to,
248                session_from,
249                session_to,
250                pseudonymization_secret,
251                encryption_secret,
252            ),
253            attribute: AttributeRekeyInfo::new(session_from, session_to, encryption_secret),
254        }
255    }
256
257    /// Reverse the transcryption info (i.e., switch the direction of the transcryption).
258    pub fn reverse(&self) -> Self {
259        Self {
260            pseudonym: self.pseudonym.reverse(),
261            attribute: self.attribute.reverse(),
262        }
263    }
264}