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}