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