scrambledb/
setup.rs

1//! # Setup
2use hacspec_lib::Randomness;
3use libcrux::hpke::{
4    kem::{GenerateKeyPair, Nsk},
5    HPKEConfig,
6};
7use oprf::coprf::{
8    coprf_online,
9    coprf_setup::{BlindingPublicKey, CoPRFEvaluatorContext, CoPRFReceiverContext},
10};
11use p256::P256Point;
12
13use crate::{
14    data_types::{BlindedPseudonymizedHandle, FinalizedPseudonym},
15    error::Error,
16};
17
18pub struct ConverterContext {
19    pub(crate) coprf_context: CoPRFEvaluatorContext,
20}
21
22/// A data store's private decryption key.
23pub struct StoreDecryptionKey(pub(crate) Vec<u8>);
24
25/// A data store's public encryption key.
26#[derive(Clone)]
27pub struct StoreEncryptionKey(pub(crate) Vec<u8>);
28
29pub struct StoreContext {
30    coprf_receiver_context: CoPRFReceiverContext,
31    pub(crate) dk: StoreDecryptionKey,
32    ek: StoreEncryptionKey,
33    k_prp: [u8; 32],
34}
35
36pub type LakeContext = StoreContext;
37pub type ProcessorContext = StoreContext;
38
39impl ConverterContext {
40    /// ## Converter Setup
41    /// On setup the converter initializes a coPRF evaluator context.
42    ///
43    /// ``` text
44    /// Inputs:
45    ///     msk: Nmsk uniformly random bytes
46    ///
47    /// Output:
48    ///     coprf_evaluator_context: coPRFEvaluatorContext
49    ///
50    /// fn setup_converter_context(msk) -> ConverterContext:
51    ///     return coPRFEvaluatorContext::new(msk)
52    /// ```
53    pub fn setup(randomness: &mut Randomness) -> Result<Self, Error> {
54        Ok(ConverterContext {
55            coprf_context: CoPRFEvaluatorContext::new(randomness)?,
56        })
57    }
58}
59
60impl StoreContext {
61    /// ## Data Store Setup
62    /// On setup, a data store initializes a coPRFReceiverContext, derives a
63    /// pair of encryption and decryption keys for the RPKE as well as a
64    /// private PRP key.
65    ///
66    /// ``` text
67    /// Inputs:
68    ///     randomness: (NcoPRFReceiver + NRPKEKeyGen + NPRP) uniformly random bytes
69    ///
70    /// Outputs:
71    ///     coprf_receiver_context: CoPRFReceiverContext
72    ///     ek: RPKE.EncryptionKey
73    ///     dk: RPKE.DecryptionKey
74    ///     k_prp: PRP.PRPKey
75    ///
76    /// fn setup(randomness) -> StoreContext:
77    ///     let coprf_receiver_context =
78    ///     CoPRFReceiverContext::new(randomness[NcoPRFReceiver]);
79    ///     let (ek, dk) = RPKE.generate_keys(randomness[NRPKEKeyGen]);
80    ///     let k_prp = PRP.KeyGen(randomness[NPRP]);
81    ///     StoreContext{
82    ///       coprf_receiver_context,
83    ///       ek,
84    ///       dk,
85    ///       k_prp
86    ///     }
87    /// ```
88    pub fn setup(randomness: &mut Randomness) -> Result<Self, Error> {
89        let receiver_context = CoPRFReceiverContext::new(randomness);
90
91        let (dk, ek) = generate_store_keys(randomness)?;
92
93        let k_prp = randomness.bytes(32)?.try_into()?;
94
95        Ok(Self {
96            coprf_receiver_context: receiver_context,
97            dk,
98            ek,
99            k_prp,
100        })
101    }
102
103    /// Given a store context generated as above, the following methods are
104    /// available:
105    ///
106    /// - Retrieve store public keys for encryption and coPRF blinding.
107    /// ``` text
108    /// Input:
109    ///     context: StoreContext
110    /// Output:
111    ///     ek: RPKE.EncryptionKey
112    ///     bpk: CoPRF.BlindingPublicKey
113    ///
114    /// fn public_keys(context):
115    ///     let ek = context.ek;
116    ///     let bpk = context.coprf_receiver_context.public_key()
117    ///     return (ek, bpk);
118    /// ```
119    pub fn public_keys(&self) -> (StoreEncryptionKey, BlindingPublicKey) {
120        (self.ek.clone(), self.coprf_receiver_context.get_bpk())
121    }
122
123    /// - Finalize Pseudonym: As part of the finalization of a split or join
124    ///   conversion the raw pseudonyms that are the unblinded result of coPRF
125    ///   evaluation are further hardened by application of a PRP.
126    ///
127    /// ``` text
128    /// Input:
129    ///     context: StoreContext
130    ///     blind_pseudonym: CoPRFBlindOutput
131    /// Output:
132    ///     pseudonym: Pseudonym
133    ///
134    /// fn finalize_pseudonym(context, blind_pseudonym):
135    ///     let raw_pseudonym =
136    ///     context.coprf_receiver_context.finalize(blind_pseudonym);
137    ///     return PRP.eval(context.k_prp, raw_pseudonym)
138    /// ```
139    pub fn finalize_pseudonym(
140        &self,
141        blind_pseudonym: BlindedPseudonymizedHandle,
142    ) -> Result<FinalizedPseudonym, Error> {
143        let raw_pseudonym =
144            coprf_online::finalize(&self.coprf_receiver_context, blind_pseudonym.0)?;
145        Ok(FinalizedPseudonym(prp::prp(
146            raw_pseudonym.raw_bytes(),
147            &self.k_prp,
148        )))
149    }
150
151    /// - Recover Raw Pseudonym: In preparation of a join conversion, the raw
152    ///   pseudonyms, i.e. coPRF outputs must be recovered from the hardened
153    ///   pseudonyms before they can be sent to the converter for blind
154    ///   conversion.
155    ///
156    ///   ``` text
157    ///   Inputs:
158    ///       context: StoreContext
159    ///       pseudonym: Pseudonym
160    ///
161    ///   Output:
162    ///       raw_pseudonym: CoPRFOutput
163    ///
164    ///   fn recover_raw_pseudonym(context, pseudonym):
165    ///       return PRP.invert(context.k_prp, pseudonym)
166    ///   ```
167    pub fn recover_raw_pseudonym(&self, pseudonym: FinalizedPseudonym) -> Result<P256Point, Error> {
168        P256Point::from_raw_bytes(prp::prp(pseudonym.0, &self.k_prp)).map_err(|e| e.into())
169    }
170}
171
172fn generate_store_keys(
173    randomness: &mut Randomness,
174) -> Result<(StoreDecryptionKey, StoreEncryptionKey), Error> {
175    let HPKEConfig(_, kem, _, _) = crate::HPKE_CONF;
176    let (hpke_sk, hpke_pk) = GenerateKeyPair(kem, randomness.bytes(Nsk(kem)).unwrap().to_vec())?;
177    Ok((StoreDecryptionKey(hpke_sk), StoreEncryptionKey(hpke_pk)))
178}