| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 |    2 // Use of this source code is governed by a BSD-style license that can be | 
 |    3 // found in the LICENSE file. | 
 |    4  | 
 |    5 #ifndef CHROME_BROWSER_METRICS_RAPPORD_H_ | 
 |    6 #define CHROME_BROWSER_METRICS_RAPPORD_H_ | 
 |    7  | 
 |    8 #include <assert.h> | 
 |    9 #include <limits.h> | 
 |   10 #include <math.h> | 
 |   11  | 
 |   12 #include <bitset> | 
 |   13 #include <map> | 
 |   14 #include <string> | 
 |   15 #include <vector> | 
 |   16  | 
 |   17 #include "crypto/hmac.h" | 
 |   18 #include "crypto/random.h" | 
 |   19 // FIXME(holte) Avoid checkdeps issue. | 
 |   20 // #include "third_party/smhasher/src/MurmurHash3.h" | 
 |   21  | 
 |   22 static inline uint32 MurmurHash3String(const std::string& str, uint32 seed) { | 
 |   23   uint32 output; | 
 |   24   // MurmurHash3_x86_32(str.data(), str.size(), seed, &output); | 
 |   25   return output; | 
 |   26 } | 
 |   27  | 
 |   28 // NOTE: These were just generated from /dev/urandom.  May be unecessary | 
 |   29 //       for murmur hash, or may be better to select carefully to help the | 
 |   30 //       hash function distribute its inputs. | 
 |   31 static const uint32_t hashSeedCount = 20; | 
 |   32 static const uint32_t mockHashSeeds[hashSeedCount] = { | 
 |   33   0xd123957d, 0x6752fc9b, 0xcb6a0102, 0x1a82ea95, | 
 |   34   0x55cb27bd, 0x0d23a17e, 0xbfb2beac, 0xbabca478, | 
 |   35   0x6d0b103c, 0x5e98bc37, 0xe73ccb9d, 0xe60c1150, | 
 |   36   0xa5f070a8, 0x91cc68c2, 0x12c919ff, 0xfec1d371, | 
 |   37   0x01b6bf4c, 0xbbe5cf2b, 0x6bd30801, 0x292956d3 | 
 |   38 }; | 
 |   39  | 
 |   40  | 
 |   41  | 
 |   42 template <size_t BitCount, size_t HashCount, int lieProbIndex, int pProbIndex, | 
 |   43     int qProbIndex> | 
 |   44 class RappordBloomFilter { | 
 |   45   public: | 
 |   46   typedef std::bitset<BitCount> bitmap_t; | 
 |   47   static const size_t MIN_BITMAP_SIZE = sizeof(uint64_t)*CHAR_BIT; | 
 |   48  | 
 |   49   RappordBloomFilter(const uint32_t seed, const std::string id) : | 
 |   50     hmac_(crypto::HMAC::SHA256) { | 
 |   51     if (!hmac_.Init(id)) { | 
 |   52       abort(); | 
 |   53     }; | 
 |   54     assert(hmac_.DigestLength() > sizeof(uint64_t)); | 
 |   55     hmac_state_ = uint64_t(BitCount * HashCount * | 
 |   56                   lieProbIndex * pProbIndex * qProbIndex * seed); | 
 |   57  | 
 |   58     const bitmap_t liebits = get_random_bitmap_for_probability_index( | 
 |   59       lieProbIndex, false); | 
 |   60     // hard-code that we lie 50%/50% on ones vs zeros | 
 |   61     lieones_ = liebits & random_bitmap(false); | 
 |   62     truthbits_ = ~liebits; | 
 |   63   } | 
 |   64  | 
 |   65   bitmap_t get(const std::vector<std::string>& strings) { | 
 |   66     return generate_rappord(get_real_bloombits(strings)); | 
 |   67   } | 
 |   68  | 
 |   69   bitmap_t get(const std::string str) { | 
 |   70     return generate_rappord(get_real_bloombits(str)); | 
 |   71   } | 
 |   72  | 
 |   73   static bitmap_t get_real_bloombits(const std::string& str) { | 
 |   74     // Get the bits of a bloomfilter for a string | 
 |   75     assert(BitCount % MIN_BITMAP_SIZE == 0); | 
 |   76     assert(HashCount < hashSeedCount); | 
 |   77     bitmap_t bloombits; | 
 |   78     for (size_t j = 0; j < HashCount; ++j) { | 
 |   79       uint32_t index = MurmurHash3String(str, mockHashSeeds[j]); | 
 |   80       bloombits.set(index % BitCount); | 
 |   81     } | 
 |   82     return bloombits; | 
 |   83   } | 
 |   84  | 
 |   85   static bitmap_t get_real_bloombits(const std::vector<std::string>& strings) { | 
 |   86     // Get the bits of a bloomfilter for all of the input strings. | 
 |   87     bitmap_t bloombits; | 
 |   88     for (size_t i = 0, len = strings.size(); i < len; ++i) { | 
 |   89       bloombits |= get_real_bloombits(strings[i]); | 
 |   90     } | 
 |   91     return bloombits; | 
 |   92   } | 
 |   93  | 
 |   94   private: | 
 |   95   bitmap_t lieones_; | 
 |   96   bitmap_t truthbits_; | 
 |   97   crypto::HMAC hmac_; | 
 |   98   uint64_t hmac_state_; | 
 |   99  | 
 |  100   // Construct a RAPPORD based on the bits set in the bloomfilter, as well as | 
 |  101   // the bits for which the current user will deterministally lie zero or one. | 
 |  102   // Requires: (~truthbits) == liebits == (liezeros | lieones) | 
 |  103   //           where (liezeros & lieones) == 0 | 
 |  104   // | 
 |  105   const bitmap_t generate_rappord(const bitmap_t& real_bloombits) { | 
 |  106     const bitmap_t zeros = get_random_bitmap_for_probability_index( | 
 |  107         pProbIndex, true); | 
 |  108     const bitmap_t ones = get_random_bitmap_for_probability_index( | 
 |  109         qProbIndex, true); | 
 |  110     const bitmap_t onebits = (real_bloombits & truthbits_) | lieones_; | 
 |  111     return (zeros & (~onebits)) | (ones & onebits); | 
 |  112   } | 
 |  113  | 
 |  114   bitmap_t random_bitmap(const bool fresh) { | 
 |  115     assert(BitCount % MIN_BITMAP_SIZE == 0); | 
 |  116     bitmap_t bits; | 
 |  117     for (size_t i = 0; i < BitCount; i += MIN_BITMAP_SIZE) { | 
 |  118       uint64_t randomBits; | 
 |  119       assert(MIN_BITMAP_SIZE/CHAR_BIT == sizeof(uint64_t)); | 
 |  120       if (!fresh) { | 
 |  121         hmacRandBytes(&randomBits); | 
 |  122       } else { | 
 |  123         crypto::RandBytes(&randomBits, sizeof(uint64_t)); | 
 |  124       } | 
 |  125  | 
 |  126       bits <<= MIN_BITMAP_SIZE; | 
 |  127       bits |= bitmap_t(randomBits); | 
 |  128     } | 
 |  129     return bits; | 
 |  130   } | 
 |  131  | 
 |  132   void hmacRandBytes(uint64_t* randomBits) { | 
 |  133     std::string state = bitmap_t(hmac_state_).to_string(); | 
 |  134     if (!hmac_.Sign(state, (unsigned char *) randomBits, sizeof(uint64_t))) { | 
 |  135       abort(); | 
 |  136     } | 
 |  137     ++hmac_state_; | 
 |  138   } | 
 |  139  | 
 |  140   // TODO(holte): change to template function | 
 |  141   bitmap_t get_random_bitmap_for_probability_index( | 
 |  142       int probIndex, const bool fresh) { | 
 |  143     switch (probIndex) { | 
 |  144       // 87.5% ones | 
 |  145     case -8: return ~(random_bitmap(fresh) & random_bitmap(fresh) & | 
 |  146         random_bitmap(fresh)); | 
 |  147       // 75% ones | 
 |  148     case -4: return ~(random_bitmap(fresh) & random_bitmap(fresh)); | 
 |  149       // 50% ones | 
 |  150     case  2: return random_bitmap(fresh); | 
 |  151       // 25% ones | 
 |  152     case  4: return random_bitmap(fresh) & random_bitmap(fresh); | 
 |  153       // 12.5% ones | 
 |  154     case  8: return random_bitmap(fresh) & random_bitmap(fresh) & | 
 |  155         random_bitmap(fresh); | 
 |  156     default: | 
 |  157       // Invalid probability index "probIndex" for coin flips | 
 |  158       abort(); | 
 |  159     } | 
 |  160   } | 
 |  161 }; | 
 |  162  | 
 |  163 #endif  // CHROME_BROWSER_METRICS_RAPPORD_H_ | 
| OLD | NEW |