xref: /aosp_15_r20/external/rappor/client/cpp/encoder.cc (revision 2abb31345f6c95944768b5222a9a5ed3fc68cc00)
1*2abb3134SXin Li // Copyright 2015 Google Inc. All rights reserved.
2*2abb3134SXin Li //
3*2abb3134SXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*2abb3134SXin Li // you may not use this file except in compliance with the License.
5*2abb3134SXin Li // You may obtain a copy of the License at
6*2abb3134SXin Li //
7*2abb3134SXin Li //     http://www.apache.org/licenses/LICENSE-2.0
8*2abb3134SXin Li //
9*2abb3134SXin Li // Unless required by applicable law or agreed to in writing, software
10*2abb3134SXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*2abb3134SXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*2abb3134SXin Li // See the License for the specific language governing permissions and
13*2abb3134SXin Li // limitations under the License.
14*2abb3134SXin Li 
15*2abb3134SXin Li #include "encoder.h"
16*2abb3134SXin Li #include "openssl_hash_impl.h"
17*2abb3134SXin Li 
18*2abb3134SXin Li #include <assert.h>
19*2abb3134SXin Li #include <stdio.h>
20*2abb3134SXin Li #include <stdarg.h>  // va_list, etc.
21*2abb3134SXin Li #include <vector>
22*2abb3134SXin Li 
23*2abb3134SXin Li namespace rappor {
24*2abb3134SXin Li 
log(const char * fmt,...)25*2abb3134SXin Li void log(const char* fmt, ...) {
26*2abb3134SXin Li   va_list args;
27*2abb3134SXin Li   va_start(args, fmt);
28*2abb3134SXin Li   vfprintf(stderr, fmt, args);
29*2abb3134SXin Li   va_end(args);
30*2abb3134SXin Li   fprintf(stderr, "\n");
31*2abb3134SXin Li }
32*2abb3134SXin Li 
33*2abb3134SXin Li //
34*2abb3134SXin Li // Functions for debugging
35*2abb3134SXin Li //
36*2abb3134SXin Li 
PrintHex(const std::vector<uint8_t> & h)37*2abb3134SXin Li static void PrintHex(const std::vector<uint8_t>& h) {
38*2abb3134SXin Li   for (size_t i = 0; i < h.size(); ++i) {
39*2abb3134SXin Li     fprintf(stderr, "%02x", h[i]);
40*2abb3134SXin Li   }
41*2abb3134SXin Li   fprintf(stderr, "\n");
42*2abb3134SXin Li }
43*2abb3134SXin Li 
44*2abb3134SXin Li // We use 1 *byte* of a HMAC-SHA256 value per BIT to generate the PRR.  SHA256
45*2abb3134SXin Li // has 32 bytes, so the max is 32 bits.
46*2abb3134SXin Li static const int kMaxBits = 32;
47*2abb3134SXin Li 
48*2abb3134SXin Li // Can't be more than the number of bytes in MD5.
49*2abb3134SXin Li static const int kMaxHashes = 16;
50*2abb3134SXin Li 
51*2abb3134SXin Li // Probabilities should be in the interval [0.0, 1.0].
CheckValidProbability(float prob,const char * var_name)52*2abb3134SXin Li static void CheckValidProbability(float prob, const char* var_name) {
53*2abb3134SXin Li   if (prob < 0.0f || prob > 1.0f) {
54*2abb3134SXin Li     log("%s should be between 0.0 and 1.0 inclusive (got %.2f)", var_name,
55*2abb3134SXin Li         prob);
56*2abb3134SXin Li     assert(false);
57*2abb3134SXin Li   }
58*2abb3134SXin Li }
59*2abb3134SXin Li 
60*2abb3134SXin Li // Used to 1) turn cohort into a string, and 2) Turn raw bits into a string.
61*2abb3134SXin Li // Return by value since it's small.
ToBigEndian(uint32_t u)62*2abb3134SXin Li static std::string ToBigEndian(uint32_t u) {
63*2abb3134SXin Li   std::string result(4, '\0');
64*2abb3134SXin Li 
65*2abb3134SXin Li   // rely on truncation to char
66*2abb3134SXin Li   result[0] = u >> 24;
67*2abb3134SXin Li   result[1] = u >> 16;
68*2abb3134SXin Li   result[2] = u >> 8;
69*2abb3134SXin Li   result[3] = u;
70*2abb3134SXin Li 
71*2abb3134SXin Li   return result;
72*2abb3134SXin Li }
73*2abb3134SXin Li 
74*2abb3134SXin Li static const char* kHmacCohortPrefix = "\x00";
75*2abb3134SXin Li static const char* kHmacPrrPrefix = "\x01";
76*2abb3134SXin Li 
77*2abb3134SXin Li 
78*2abb3134SXin Li //
79*2abb3134SXin Li // Encoder
80*2abb3134SXin Li //
81*2abb3134SXin Li 
AssignCohort(const Deps & deps,int num_cohorts)82*2abb3134SXin Li uint32_t Encoder::AssignCohort(const Deps& deps, int num_cohorts) {
83*2abb3134SXin Li   std::vector<uint8_t> sha256;
84*2abb3134SXin Li   if (!deps.hmac_func_(deps.client_secret_, kHmacCohortPrefix, &sha256)) {
85*2abb3134SXin Li     log("HMAC failed");
86*2abb3134SXin Li     assert(false);
87*2abb3134SXin Li   }
88*2abb3134SXin Li 
89*2abb3134SXin Li   // Either we are using SHA256 to have exactly 32 bytes,
90*2abb3134SXin Li   // or we're using HmacDrbg for any number of bytes.
91*2abb3134SXin Li   if ((sha256.size() == kMaxBits)
92*2abb3134SXin Li       || (deps.hmac_func_ == rappor::HmacDrbg)) {
93*2abb3134SXin Li     // Hash size ok.
94*2abb3134SXin Li   } else {
95*2abb3134SXin Li     log("Bad hash size.");
96*2abb3134SXin Li     assert(false);
97*2abb3134SXin Li   }
98*2abb3134SXin Li 
99*2abb3134SXin Li   // Interpret first 4 bytes of sha256 as a uint32_t.
100*2abb3134SXin Li   uint32_t c = *(reinterpret_cast<uint32_t*>(sha256.data()));
101*2abb3134SXin Li   // e.g. for 128 cohorts, 0x80 - 1 = 0x7f
102*2abb3134SXin Li   uint32_t cohort_mask = num_cohorts - 1;
103*2abb3134SXin Li   return c & cohort_mask;
104*2abb3134SXin Li }
105*2abb3134SXin Li 
Encoder(const std::string & encoder_id,const Params & params,const Deps & deps)106*2abb3134SXin Li Encoder::Encoder(const std::string& encoder_id, const Params& params,
107*2abb3134SXin Li                  const Deps& deps)
108*2abb3134SXin Li     : encoder_id_(encoder_id),
109*2abb3134SXin Li       params_(params),
110*2abb3134SXin Li       deps_(deps),
111*2abb3134SXin Li       cohort_(AssignCohort(deps, params.num_cohorts_)),
112*2abb3134SXin Li       cohort_str_(ToBigEndian(cohort_)) {
113*2abb3134SXin Li 
114*2abb3134SXin Li   if (params_.num_bits_ <= 0) {
115*2abb3134SXin Li     log("num_bits must be positive");
116*2abb3134SXin Li     assert(false);
117*2abb3134SXin Li   }
118*2abb3134SXin Li   if (params_.num_hashes_ <= 0) {
119*2abb3134SXin Li     log("num_hashes must be positive");
120*2abb3134SXin Li     assert(false);
121*2abb3134SXin Li   }
122*2abb3134SXin Li   if (params_.num_cohorts_ <= 0) {
123*2abb3134SXin Li     log("num_cohorts must be positive");
124*2abb3134SXin Li     assert(false);
125*2abb3134SXin Li   }
126*2abb3134SXin Li 
127*2abb3134SXin Li   // Check Maximum values.
128*2abb3134SXin Li   if (deps_.hmac_func_ == rappor::HmacDrbg) {
129*2abb3134SXin Li     // Using HmacDrbg
130*2abb3134SXin Li     if (params_.num_bits_ % 8 != 0) {
131*2abb3134SXin Li       log("num_bits (%d) must be divisible by 8 when using HmacDrbg.",
132*2abb3134SXin Li           params.num_bits_);
133*2abb3134SXin Li       assert(false);
134*2abb3134SXin Li     }
135*2abb3134SXin Li   } else {
136*2abb3134SXin Li     // Using SHA256
137*2abb3134SXin Li     if (params_.num_bits_ > kMaxBits) {
138*2abb3134SXin Li         log("num_bits (%d) can't be greater than %d", params_.num_bits_,
139*2abb3134SXin Li             kMaxBits);
140*2abb3134SXin Li         assert(false);
141*2abb3134SXin Li     }
142*2abb3134SXin Li   }
143*2abb3134SXin Li 
144*2abb3134SXin Li   if (params_.num_hashes_ > kMaxHashes) {
145*2abb3134SXin Li     log("num_hashes (%d) can't be greater than %d", params_.num_hashes_,
146*2abb3134SXin Li         kMaxHashes);
147*2abb3134SXin Li     assert(false);
148*2abb3134SXin Li   }
149*2abb3134SXin Li   int m = params_.num_cohorts_;
150*2abb3134SXin Li   if ((m & (m - 1)) != 0) {
151*2abb3134SXin Li     log("num_cohorts (%d) must be a power of 2 (and not 0)", m);
152*2abb3134SXin Li     assert(false);
153*2abb3134SXin Li   }
154*2abb3134SXin Li   // TODO: check max cohorts?
155*2abb3134SXin Li 
156*2abb3134SXin Li   CheckValidProbability(params_.prob_f_, "prob_f");
157*2abb3134SXin Li   CheckValidProbability(params_.prob_p_, "prob_p");
158*2abb3134SXin Li   CheckValidProbability(params_.prob_q_, "prob_q");
159*2abb3134SXin Li }
160*2abb3134SXin Li 
MakeBloomFilter(const std::string & value,Bits * bloom_out) const161*2abb3134SXin Li bool Encoder::MakeBloomFilter(const std::string& value, Bits* bloom_out) const {
162*2abb3134SXin Li   const int num_bits = params_.num_bits_;
163*2abb3134SXin Li   const int num_hashes = params_.num_hashes_;
164*2abb3134SXin Li 
165*2abb3134SXin Li   Bits bloom = 0;
166*2abb3134SXin Li 
167*2abb3134SXin Li   // 4 byte cohort string + true value
168*2abb3134SXin Li   std::string hash_input(cohort_str_ + value);
169*2abb3134SXin Li 
170*2abb3134SXin Li   // First do hashing.
171*2abb3134SXin Li   std::vector<uint8_t> hash_output;
172*2abb3134SXin Li   deps_.hash_func_(hash_input, &hash_output);
173*2abb3134SXin Li 
174*2abb3134SXin Li   // Error check
175*2abb3134SXin Li   if (hash_output.size() < static_cast<size_t>(num_hashes)) {
176*2abb3134SXin Li     log("Hash function didn't return enough bytes");
177*2abb3134SXin Li     return false;
178*2abb3134SXin Li   }
179*2abb3134SXin Li 
180*2abb3134SXin Li   // To determine which bit to set in the bloom filter, use a byte of the MD5.
181*2abb3134SXin Li   for (int i = 0; i < num_hashes; ++i) {
182*2abb3134SXin Li     int bit_to_set = hash_output[i] % num_bits;
183*2abb3134SXin Li     bloom |= 1 << bit_to_set;
184*2abb3134SXin Li   }
185*2abb3134SXin Li 
186*2abb3134SXin Li   *bloom_out = bloom;
187*2abb3134SXin Li   return true;
188*2abb3134SXin Li }
189*2abb3134SXin Li 
190*2abb3134SXin Li // Write a Bloom filter into a vector of bytes, used for num_bits > 32.
MakeBloomFilter(const std::string & value,std::vector<uint8_t> * bloom_out) const191*2abb3134SXin Li bool Encoder::MakeBloomFilter(const std::string& value,
192*2abb3134SXin Li                               std::vector<uint8_t>* bloom_out) const {
193*2abb3134SXin Li   const int num_bits = params_.num_bits_;
194*2abb3134SXin Li   const int num_hashes = params_.num_hashes_;
195*2abb3134SXin Li 
196*2abb3134SXin Li   bloom_out->resize(params_.num_bits_ / 8, 0);
197*2abb3134SXin Li 
198*2abb3134SXin Li   // Generate the hash.
199*2abb3134SXin Li   std::vector<uint8_t> hash_output;
200*2abb3134SXin Li   deps_.hash_func_(std::string(cohort_str_ + value), &hash_output);
201*2abb3134SXin Li 
202*2abb3134SXin Li   // Check that we have enough bytes of hash available.
203*2abb3134SXin Li   int exponent = 0;
204*2abb3134SXin Li   int bytes_needed = 0;
205*2abb3134SXin Li   while ((1 << exponent) < num_bits) {
206*2abb3134SXin Li     exponent++;
207*2abb3134SXin Li   }
208*2abb3134SXin Li   bytes_needed = ((exponent - 1) / 8) + 1;
209*2abb3134SXin Li   if (bytes_needed > 4) {
210*2abb3134SXin Li     log("Can only use 4 bytes of hash at a time, needed %d "
211*2abb3134SXin Li         "to address %d bits.", bytes_needed, num_bits);
212*2abb3134SXin Li     return false;
213*2abb3134SXin Li   }
214*2abb3134SXin Li   if (hash_output.size() < static_cast<size_t>(bytes_needed * num_hashes)) {
215*2abb3134SXin Li     log("Hash function returned %d bytes, but we needed "
216*2abb3134SXin Li         "%d bytes * %d hashes. Choose lower num_hashes or "
217*2abb3134SXin Li         "a different hash function.",
218*2abb3134SXin Li         hash_output.size(), bytes_needed, num_hashes);
219*2abb3134SXin Li     return false;
220*2abb3134SXin Li   }
221*2abb3134SXin Li 
222*2abb3134SXin Li   // To determine which bit to set in the Bloom filter, use 1 or more
223*2abb3134SXin Li   // bytes of the MD5.
224*2abb3134SXin Li   int hash_byte = 0;
225*2abb3134SXin Li   for (int i = 0; i < num_hashes; ++i) {
226*2abb3134SXin Li     int bit_to_set = 0;
227*2abb3134SXin Li     for (int j = 0; j < bytes_needed; ++j) {
228*2abb3134SXin Li       bit_to_set |= hash_output[hash_byte] << (j * 8);
229*2abb3134SXin Li       ++hash_byte;
230*2abb3134SXin Li     }
231*2abb3134SXin Li     bit_to_set %= num_bits;
232*2abb3134SXin Li     // Start at end of array to be consistent with the Bits implementation.
233*2abb3134SXin Li     int index = (bloom_out->size() - 1) - (bit_to_set / 8);
234*2abb3134SXin Li     (*bloom_out)[index] |= 1 << (bit_to_set % 8);
235*2abb3134SXin Li   }
236*2abb3134SXin Li   return true;
237*2abb3134SXin Li }
238*2abb3134SXin Li 
239*2abb3134SXin Li // Helper method for PRR
GetPrrMasks(const Bits bits,Bits * uniform_out,Bits * f_mask_out) const240*2abb3134SXin Li bool Encoder::GetPrrMasks(const Bits bits, Bits* uniform_out,
241*2abb3134SXin Li                           Bits* f_mask_out) const {
242*2abb3134SXin Li   // Create HMAC(secret, value), and use its bits to construct f_mask and
243*2abb3134SXin Li   // uniform bits.
244*2abb3134SXin Li   std::vector<uint8_t> sha256;
245*2abb3134SXin Li 
246*2abb3134SXin Li   std::string hmac_value = kHmacPrrPrefix + encoder_id_ + ToBigEndian(bits);
247*2abb3134SXin Li 
248*2abb3134SXin Li   deps_.hmac_func_(deps_.client_secret_, hmac_value, &sha256);
249*2abb3134SXin Li   if (sha256.size() != kMaxBits) {  // sanity check
250*2abb3134SXin Li     return false;
251*2abb3134SXin Li   }
252*2abb3134SXin Li 
253*2abb3134SXin Li   // We should have already checked this.
254*2abb3134SXin Li   if (params_.num_bits_ > kMaxBits) {
255*2abb3134SXin Li     log("num_bits exceeds maximum.");
256*2abb3134SXin Li     assert(false);
257*2abb3134SXin Li   }
258*2abb3134SXin Li 
259*2abb3134SXin Li   uint8_t threshold128 = static_cast<uint8_t>(params_.prob_f_ * 128);
260*2abb3134SXin Li 
261*2abb3134SXin Li   Bits uniform = 0;
262*2abb3134SXin Li   Bits f_mask = 0;
263*2abb3134SXin Li 
264*2abb3134SXin Li   for (int i = 0; i < params_.num_bits_; ++i) {
265*2abb3134SXin Li     uint8_t byte = sha256[i];
266*2abb3134SXin Li 
267*2abb3134SXin Li     uint8_t u_bit = byte & 0x01;  // 1 bit of entropy
268*2abb3134SXin Li     uniform |= (u_bit << i);  // maybe set bit in mask
269*2abb3134SXin Li 
270*2abb3134SXin Li     uint8_t rand128 = byte >> 1;  // 7 bits of entropy
271*2abb3134SXin Li     uint8_t noise_bit = (rand128 < threshold128);
272*2abb3134SXin Li     f_mask |= (noise_bit << i);  // maybe set bit in mask
273*2abb3134SXin Li   }
274*2abb3134SXin Li 
275*2abb3134SXin Li   *uniform_out = uniform;
276*2abb3134SXin Li   *f_mask_out = f_mask;
277*2abb3134SXin Li   return true;
278*2abb3134SXin Li }
279*2abb3134SXin Li 
_EncodeBitsInternal(const Bits bits,Bits * prr_out,Bits * irr_out) const280*2abb3134SXin Li bool Encoder::_EncodeBitsInternal(const Bits bits, Bits* prr_out,
281*2abb3134SXin Li                                   Bits* irr_out) const {
282*2abb3134SXin Li   // Compute Permanent Randomized Response (PRR).
283*2abb3134SXin Li   Bits uniform;
284*2abb3134SXin Li   Bits f_mask;
285*2abb3134SXin Li   if (!GetPrrMasks(bits, &uniform, &f_mask)) {
286*2abb3134SXin Li     log("GetPrrMasks failed");
287*2abb3134SXin Li     return false;
288*2abb3134SXin Li   }
289*2abb3134SXin Li 
290*2abb3134SXin Li   Bits prr = (bits & ~f_mask) | (uniform & f_mask);
291*2abb3134SXin Li   *prr_out = prr;
292*2abb3134SXin Li 
293*2abb3134SXin Li   // Compute Instantaneous Randomized Response (IRR).
294*2abb3134SXin Li 
295*2abb3134SXin Li   // NOTE: These can fail if say a read() from /dev/urandom fails.
296*2abb3134SXin Li   Bits p_bits;
297*2abb3134SXin Li   Bits q_bits;
298*2abb3134SXin Li   if (!deps_.irr_rand_.GetMask(params_.prob_p_, params_.num_bits_, &p_bits)) {
299*2abb3134SXin Li     log("PMask failed");
300*2abb3134SXin Li     return false;
301*2abb3134SXin Li   }
302*2abb3134SXin Li   if (!deps_.irr_rand_.GetMask(params_.prob_q_, params_.num_bits_, &q_bits)) {
303*2abb3134SXin Li     log("QMask failed");
304*2abb3134SXin Li     return false;
305*2abb3134SXin Li   };
306*2abb3134SXin Li 
307*2abb3134SXin Li   Bits irr = (p_bits & ~prr) | (q_bits & prr);
308*2abb3134SXin Li   *irr_out = irr;
309*2abb3134SXin Li 
310*2abb3134SXin Li   return true;
311*2abb3134SXin Li }
312*2abb3134SXin Li 
_EncodeStringInternal(const std::string & value,Bits * bloom_out,Bits * prr_out,Bits * irr_out) const313*2abb3134SXin Li bool Encoder::_EncodeStringInternal(const std::string& value, Bits* bloom_out,
314*2abb3134SXin Li     Bits* prr_out, Bits* irr_out) const {
315*2abb3134SXin Li   if (!MakeBloomFilter(value, bloom_out)) {
316*2abb3134SXin Li     log("Bloom filter calculation failed");
317*2abb3134SXin Li     return false;
318*2abb3134SXin Li   }
319*2abb3134SXin Li   return _EncodeBitsInternal(*bloom_out, prr_out, irr_out);
320*2abb3134SXin Li }
321*2abb3134SXin Li 
EncodeBits(const Bits bits,Bits * irr_out) const322*2abb3134SXin Li bool Encoder::EncodeBits(const Bits bits, Bits* irr_out) const {
323*2abb3134SXin Li   Bits unused_prr;
324*2abb3134SXin Li   return _EncodeBitsInternal(bits, &unused_prr, irr_out);
325*2abb3134SXin Li }
326*2abb3134SXin Li 
EncodeString(const std::string & value,Bits * irr_out) const327*2abb3134SXin Li bool Encoder::EncodeString(const std::string& value, Bits* irr_out) const {
328*2abb3134SXin Li   Bits unused_bloom;
329*2abb3134SXin Li   Bits unused_prr;
330*2abb3134SXin Li   return _EncodeStringInternal(value, &unused_bloom, &unused_prr, irr_out);
331*2abb3134SXin Li }
332*2abb3134SXin Li 
shifted(const Bits & bits,const int & index)333*2abb3134SXin Li static uint8_t shifted(const Bits& bits, const int& index) {
334*2abb3134SXin Li   // For an array of bytes, select the appopriate byte from a 4-byte
335*2abb3134SXin Li   // integer value. Bytes are enumerated in big-endian order, i.e.
336*2abb3134SXin Li   // index = 0 is the MSB, index = 3 is the LSB.
337*2abb3134SXin Li   int shift = 8 * (3 - (index % 4)); // Byte 0 shifts by 24 bits, 1 by 16, etc.
338*2abb3134SXin Li   return (uint8_t)((bits >> shift) & 0xFF);  // Return the correct byte.
339*2abb3134SXin Li }
340*2abb3134SXin Li 
EncodeString(const std::string & value,std::vector<uint8_t> * irr_out) const341*2abb3134SXin Li bool Encoder::EncodeString(const std::string& value,
342*2abb3134SXin Li                            std::vector<uint8_t>* irr_out) const {
343*2abb3134SXin Li   std::vector<uint8_t> bloom_out;
344*2abb3134SXin Li   std::vector<uint8_t> hmac_out;
345*2abb3134SXin Li   std::vector<uint8_t> uniform;
346*2abb3134SXin Li   std::vector<uint8_t> f_mask;
347*2abb3134SXin Li   const int num_bits = params_.num_bits_;
348*2abb3134SXin Li 
349*2abb3134SXin Li   uniform.resize(num_bits / 8, 0);
350*2abb3134SXin Li   f_mask.resize(num_bits / 8, 0);
351*2abb3134SXin Li   irr_out->resize(num_bits / 8, 0);
352*2abb3134SXin Li 
353*2abb3134SXin Li   // Set bloom_out.
354*2abb3134SXin Li   if (!MakeBloomFilter(value, &bloom_out)) {
355*2abb3134SXin Li     log("Bloom filter calculation failed");
356*2abb3134SXin Li     return false;
357*2abb3134SXin Li   }
358*2abb3134SXin Li 
359*2abb3134SXin Li   // Set hmac_out.
360*2abb3134SXin Li   hmac_out.resize(num_bits);  // Signal to HmacDrbg about desired output size.
361*2abb3134SXin Li   // Call HmacDrbg
362*2abb3134SXin Li   std::string hmac_value =  kHmacPrrPrefix + encoder_id_;
363*2abb3134SXin Li   for (int i = 0; i < bloom_out.size(); ++i) {
364*2abb3134SXin Li     hmac_value.append(reinterpret_cast<char *>(&bloom_out[i]), 1);
365*2abb3134SXin Li   }
366*2abb3134SXin Li   deps_.hmac_func_(deps_.client_secret_, hmac_value, &hmac_out);
367*2abb3134SXin Li   if (hmac_out.size() != num_bits) {
368*2abb3134SXin Li     log("Needed %d bytes from Hmac function, received %d bytes.",
369*2abb3134SXin Li         num_bits, hmac_out.size());
370*2abb3134SXin Li     return false;
371*2abb3134SXin Li   }
372*2abb3134SXin Li 
373*2abb3134SXin Li   // We'll be using 7 bits of each byte of the MAC as our random
374*2abb3134SXin Li   // number for the f_mask.
375*2abb3134SXin Li   uint8_t threshold128 = static_cast<uint8_t>(params_.prob_f_ * 128);
376*2abb3134SXin Li 
377*2abb3134SXin Li   // Construct uniform and f_mask bitwise.
378*2abb3134SXin Li   for (int i = 0; i < num_bits; i++) {
379*2abb3134SXin Li     uint8_t byte = hmac_out[i];
380*2abb3134SXin Li     uint8_t u_bit = byte & 0x01;  // 1 bit of entropy.
381*2abb3134SXin Li     int vector_index = (num_bits - 1 - i) / 8;
382*2abb3134SXin Li     uint8_t rand128 = byte >> 1;  // 7 bits of entropy.
383*2abb3134SXin Li     uint8_t noise_bit = (rand128 < threshold128);
384*2abb3134SXin Li     uniform[vector_index] |= (u_bit << (i % 8));
385*2abb3134SXin Li     f_mask[vector_index] |= (noise_bit << (i % 8));
386*2abb3134SXin Li   }
387*2abb3134SXin Li 
388*2abb3134SXin Li   for (int i = 0; i < bloom_out.size(); i++) {
389*2abb3134SXin Li     Bits p_bits;
390*2abb3134SXin Li     Bits q_bits;
391*2abb3134SXin Li     uint8_t prr;
392*2abb3134SXin Li     prr = (bloom_out[i] & ~f_mask[i]) | (uniform[i] & f_mask[i]);
393*2abb3134SXin Li     // GetMask operates on Uint32, so we generate a new p_bits every 4
394*2abb3134SXin Li     // bytes, and use each of its bytes once.
395*2abb3134SXin Li     if (i % 4 == 0) {
396*2abb3134SXin Li       // Need new p_bits, q_bits values to work with.
397*2abb3134SXin Li       if (!deps_.irr_rand_.GetMask(params_.prob_p_, 32, &p_bits)) {
398*2abb3134SXin Li         log("PMask failed");
399*2abb3134SXin Li         return false;
400*2abb3134SXin Li       }
401*2abb3134SXin Li       if (!deps_.irr_rand_.GetMask(params_.prob_q_, 32, &q_bits)) {
402*2abb3134SXin Li         log("QMask failed");
403*2abb3134SXin Li         return false;
404*2abb3134SXin Li       }
405*2abb3134SXin Li     }
406*2abb3134SXin Li     (*irr_out)[i] = (shifted(p_bits, i) & ~prr)
407*2abb3134SXin Li         | (shifted(q_bits, i) & prr);
408*2abb3134SXin Li   }
409*2abb3134SXin Li }
410*2abb3134SXin Li 
set_cohort(uint32_t cohort)411*2abb3134SXin Li void Encoder::set_cohort(uint32_t cohort) {
412*2abb3134SXin Li   cohort_ = cohort;
413*2abb3134SXin Li   cohort_str_ = ToBigEndian(cohort_);
414*2abb3134SXin Li }
415*2abb3134SXin Li 
416*2abb3134SXin Li }  // namespace rappor
417