SeComLib
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Macros Pages
private_recommendations_data_packing/client.cpp
Go to the documentation of this file.
1 /*
2 SeComLib
3 Copyright 2012-2013 TU Delft, Information Security & Privacy Lab (http://isplab.tudelft.nl/)
4 
5 Contributors:
6 Inald Lagendijk (R.L.Lagendijk@TUDelft.nl)
7 Mihai Todor (todormihai@gmail.com)
8 Thijs Veugen (P.J.M.Veugen@tudelft.nl)
9 Zekeriya Erkin (z.erkin@tudelft.nl)
10 
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14 
15 http://www.apache.org/licenses/LICENSE-2.0
16 
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
30 #include "client.h"
31 
32 namespace SeComLib {
33 namespace PrivateRecommendationsDataPacking {
37  const std::string Client::configurationPath("PrivateRecommendationsDataPacking");
38 
48  Client::Client (const std::shared_ptr<ServiceProvider> &serviceProvider, const std::shared_ptr<PrivacyServiceProvider> &privacyServiceProvider, const PaillierPublicKey &publicKey) :
49  serviceProvider(serviceProvider),
50  privacyServiceProvider(privacyServiceProvider),
51  paillierCryptoProvider(publicKey),
52  userCount(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".userCount")),
53  itemCount(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".itemCount")),
54  denselyRatedItemCount(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".denselyRatedItemCount")),
55  ratingBitSize(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".t")),
56  scaledNormalizedRatingBitSize(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".scaledNormalizedRatingBitSize")),
57  digitsToPreserve(Utils::Config::GetInstance().GetParameter<unsigned int>(configurationPath + ".digitsToPreserve")),
58  kappa(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".BlindingFactorCache.kappa")),
59  hatL(Utils::Config::GetInstance().GetParameter<size_t>(configurationPath + ".hatL")),
60  ratingsFilePath(Utils::Config::GetInstance().GetParameter<std::string>(configurationPath + ".ratingsFilePath")),
61  LdecryptionBlindingFactorCache(paillierCryptoProvider, BlindingFactorCacheParameters(configurationPath + ".BlindingFactorCache", BigInteger(static_cast<unsigned long>(userCount - 1)).GetSize())),//compute the number of bits required to store the maximum value for L
62  URSumDecryptionBlindingFactorCache(paillierCryptoProvider, BlindingFactorCacheParameters(configurationPath + ".BlindingFactorCache", serviceProvider->GetMaxPackedBuckets() * serviceProvider->GetBucketSize())) {
64  this->emptyBuckets = this->computeEmptyBuckets(this->hatL);
65 
67  std::ifstream ratingsFile(this->ratingsFilePath);
68  if (!ratingsFile.is_open()) {
69  throw std::runtime_error("Can't open the ratings file.");
70  }
71  std::string line;
72  //foreach user
73  while (std::getline(ratingsFile, line)) {
74  std::istringstream lineStream(line);
75 
76  ServiceProvider::EncryptedUserData userNormalizedScaledRatings;
77  std::deque<unsigned long> userRatings;
78  double squaredSum = 0.0;
79 
80  for (size_t item = 0; item < this->denselyRatedItemCount; ++item) {
81  //fetch the value
82  unsigned long rating;
83  lineStream >> rating;
84 
85  squaredSum += static_cast<double>(rating * rating);
86 
87  userRatings.emplace_back(rating);
88  }
89 
90  double denominator = std::sqrt(squaredSum);
91  for (size_t item = 0; item < this->denselyRatedItemCount; ++item) {
92  double normalizedValue = static_cast<double>(userRatings[item]) / denominator;
93  //truncate the remaining digits after scaling
94  userNormalizedScaledRatings.emplace_back(this->paillierCryptoProvider.EncryptInteger(BigInteger(normalizedValue, this->digitsToPreserve, true)));
95  }
96  this->normalizedScaledRatings.emplace_back(userNormalizedScaledRatings);
97 
98  std::deque<unsigned long> userPlaintextSparseRatings;
99 
100  //fetch the value
101  unsigned long rating;
102  while (lineStream >> rating) {
103  userPlaintextSparseRatings.emplace_back(rating);
104  }
105  this->plaintextSparseRatings.emplace_back(userPlaintextSparseRatings);
106 
108  this->sparseRatings.emplace_back(this->packUserSparseRatings(this->plaintextSparseRatings.back(), this->emptyBuckets));
109  }
110 
111  #if 0//auto-generate ratings
112  for (size_t user = 0; user < this->userCount; ++user) {
114  ServiceProvider::EncryptedUserData userNormalizedScaledRatings;
115  std::deque<unsigned long> userRatings;
116  double squaredSum = 0.0;
117  for (size_t item = 0; item < this->denselyRatedItemCount; ++item) {
118  //insert random values > 0 and <= max
119  BigInteger random;
120  do {
121  random = RandomProvider::GetInstance().GetRandomInteger(ratingBitSize);
122  }
123  while (random == 0);
124  unsigned long randomValue = random.ToUnsignedLong();
125 
126  squaredSum += static_cast<double>(randomValue * randomValue);
127 
128  userRatings.emplace_back(randomValue);
129  }
130 
131  double denominator = std::sqrt(squaredSum);
132  for (size_t item = 0; item < this->denselyRatedItemCount; ++item) {
133  double normalizedValue = static_cast<double>(userRatings[item]) / denominator;
134  //truncate the remaining digits after scaling
135  userNormalizedScaledRatings.emplace_back(this->paillierCryptoProvider.EncryptInteger(BigInteger(normalizedValue, this->digitsToPreserve, true)));
136  }
137  this->normalizedScaledRatings.emplace_back(userNormalizedScaledRatings);
138 
139  std::deque<unsigned long> userPlaintextSparseRatings;
140  for (size_t item = this->denselyRatedItemCount; item < this->itemCount; ++item) {
141  //generate random values >= 0 and <= max
142  userPlaintextSparseRatings.emplace_back(RandomProvider::GetInstance().GetRandomInteger(ratingBitSize).ToUnsignedLong());
143  }
144  this->plaintextSparseRatings.emplace_back(userPlaintextSparseRatings);
145 
147  this->sparseRatings.emplace_back(this->packUserSparseRatings(this->plaintextSparseRatings.back(), this->emptyBuckets));
148  }
149  #endif
150 
151  }
152 
157  return this->normalizedScaledRatings;
158  }
159 
164  return this->sparseRatings;
165  }
166 
171  #ifdef FIRST_USER_ONLY
172  for (size_t user = 0; user < 1; ++user) {
173  #else
174  for (size_t user = 0; user < this->userCount; ++user) {
175  #endif
176  //measure the time it takes to decrypt the recommendations for each user
177  Utils::CpuTimer recommendationsProcessingTimer;
178 
179  /*
180  std::cout << "User " << user << ":" << std::endl << std::endl;
181  */
182 
184  Paillier::Ciphertext encryptedL = this->serviceProvider->GetEncryptedL(user);
185 
186  const BlindingFactorContainer &LBlindingFactor = this->LdecryptionBlindingFactorCache.Pop();
187 
189  unsigned long L = (this->privacyServiceProvider->SecureDecryption(encryptedL + LBlindingFactor.encryptedR) - LBlindingFactor.r).ToUnsignedLong();
190 
191  /*
192  std::cout << "L: " << L << std::endl;
193  */
194 
195  ServiceProvider::PackedData encryptedURSum;
196  std::deque<BigInteger> userEmptyBuckets = this->emptyBuckets;
197  if (L == 0) {
198  std::cout << "No similar users found." << std::endl;
199  continue;
200  }
202  else if (L < this->hatL) {
203  encryptedURSum = this->serviceProvider->GetEncryptedURSum(user);
204  }
206  else {
207  std::cout << "hatL is too small!" << std::endl;
208  continue;
209  /*
211  userEmptyBuckets = this->computeEmptyBuckets(L);
212 
214  this->sparseRatings[user] = this->packUserSparseRatings(this->plaintextSparseRatings[user], userEmptyBuckets);
215 
217  encryptedURSum = this->serviceProvider->ComputeURSum(user, this->sparseRatings[user]);
218  */
219  }
220 
222  std::vector<unsigned long> URSum;
223  size_t bucketCount = 0;
224  for (ServiceProvider::PackedData::iterator encryptedURSumIterator = encryptedURSum.begin(); encryptedURSumIterator != encryptedURSum.end(); ++encryptedURSumIterator) {
225  const BlindingFactorContainer &URSumBlindingFactor = this->URSumDecryptionBlindingFactorCache.Pop();
226 
228  BigInteger packedURSum = this->privacyServiceProvider->SecureDecryption(*encryptedURSumIterator + URSumBlindingFactor.encryptedR) - URSumBlindingFactor.r;
229 
231  for (size_t bucketIndex = 0; bucketIndex < userEmptyBuckets.size() && bucketCount < this->itemCount - this->denselyRatedItemCount; ++bucketIndex) {
232  if (bucketIndex < userEmptyBuckets.size() - 1) {
233  URSum.push_back(((packedURSum % userEmptyBuckets[bucketIndex + 1]) / userEmptyBuckets[bucketIndex]).ToUnsignedLong());
234  }
235  else {
236  URSum.push_back((packedURSum / userEmptyBuckets[bucketIndex]).ToUnsignedLong());
237  }
238  ++bucketCount;
239  }
240  }
241 
242  /*
243  std::cout << "UR_sum:" << std::endl;
244  for (std::vector<unsigned long>::const_iterator URSumIterator = URSum.begin(); URSumIterator != URSum.end(); ++URSumIterator) {
245  std::cout << *URSumIterator << std::endl;
246  }
247 
248  std::cout << "Recommendations:" << std::endl;
249  for (std::vector<unsigned long>::const_iterator URSumIterator = URSum.begin(); URSumIterator != URSum.end(); ++URSumIterator) {
250  std::cout << static_cast<double>(*URSumIterator) / static_cast<double>(L) << std::endl;
251  }
252  */
253 
254  std::cout << "Processed recommendations for user " << user << " in " << recommendationsProcessingTimer.ToString() << std::endl;
255  }
256  }
257 
262  std::deque<BigInteger> Client::computeEmptyBuckets (const size_t L) const {
263  std::deque<BigInteger> output;
264 
266  unsigned long ceilLogBaseTwoHatL = static_cast<unsigned long>(std::ceil(std::log(static_cast<double>(L)) / std::log(2.0)));//change base from e to 2 and round up to the nearest integer
267 
269  size_t bucketSize = this->ratingBitSize + ceilLogBaseTwoHatL;
270 
275  size_t maxPackedBuckets = (this->paillierCryptoProvider.GetMessageSpaceSize() - this->kappa - 2) / bucketSize;
276 
278  BigInteger one(1);
279  for (size_t i = 0; i < maxPackedBuckets; ++i) {
280  output.emplace_back(one << (static_cast<unsigned long>(i * bucketSize)));
281  }
282 
283  return output;
284  }
285 
291  ServiceProvider::PackedData Client::packUserSparseRatings (const std::deque<unsigned long> &userPlaintextSparseRatings, const std::deque<BigInteger> &userEmptyBuckets) const {
292  ServiceProvider::PackedData userSparseRatings;
293  BigInteger packedBuckets;
294  size_t bucketCount = 0;
295  for (std::deque<unsigned long>::const_iterator rating = userPlaintextSparseRatings.begin(); rating != userPlaintextSparseRatings.end(); ++rating) {
296  //the bucket container is empty, so we assign to it the next value
297  if (0 == bucketCount) {
298  packedBuckets = *rating;
299  }
300  //the bucket container is not empty, so we add buckets to it
301  else {
302  packedBuckets += userEmptyBuckets[bucketCount] * (*rating);
303  }
304 
305  //if all the buckets inside the container are full, encrypt it and reset the bucket counter
306  if (bucketCount == userEmptyBuckets.size() - 1) {
307  userSparseRatings.emplace_back(this->paillierCryptoProvider.EncryptInteger(packedBuckets));
308  bucketCount = 0;
309  }
310  else {
311  ++bucketCount;
312  }
313  }
314  //store the last packed buckets
315  if (bucketCount > 0) {
316  userSparseRatings.emplace_back(this->paillierCryptoProvider.EncryptInteger(packedBuckets));
317  }
318 
319  return userSparseRatings;
320  }
321 
322 }//namespace PrivateRecommendationsDataPacking
323 }//namespace SeComLib
std::deque< BigInteger > emptyBuckets
Empty buckets , where is the bit size of the ratings.
const ServiceProvider::PackedItems & GetSparseRatings() const
Get .
RandomizerCache< BlindingFactorContainer > URSumDecryptionBlindingFactorCache
decryption blinding factor cache instance
RandomizerCache< BlindingFactorContainer > LdecryptionBlindingFactorCache
decryption blinding factor cache instance
void ComputeRecommendations()
Interact with the server(s) to extract the recommendations for every user.
unsigned int digitsToPreserve
Number of digits preserved from the normalized user ratings.
std::deque< EncryptedUserData > EncryptedUserDataContainer
Container for encrypted user data.
std::deque< Paillier::Ciphertext > EncryptedUserData
Encrypted user data.
virtual T_Ciphertext EncryptInteger(const BigInteger &plaintext) const
Encrypt an integer and apply randomization.
const std::shared_ptr< ServiceProvider > serviceProvider
A reference to the ServiceProvider.
const std::shared_ptr< PrivacyServiceProvider > privacyServiceProvider
A reference to the PrivacyServiceProvider.
Utilitary class providing algorithm timing functionality.
Definition: cpu_timer.h:47
static const std::string configurationPath
Service Provider configuration path.
std::string ToString() const
Returns the elapsed user process time as a formatted string (HH::MM::SS.mmm)
Definition: cpu_timer.cpp:63
std::deque< BigInteger > computeEmptyBuckets(const size_t L) const
Computes the empty buckets .
virtual size_t GetMessageSpaceSize() const
Returns the message space bit size.
Definition: paillier.cpp:283
size_t kappa
The security parameter for the secure comparison protocol (in bits)
std::string ratingsFilePath
The path to the file containing precomputed ratings.
ServiceProvider::PackedData packUserSparseRatings(const std::deque< unsigned long > &userPlaintextSparseRatings, const std::deque< BigInteger > &userEmptyBuckets) const
Pack the sparse ratings for one user.
Client(const std::shared_ptr< ServiceProvider > &serviceProvider, const std::shared_ptr< PrivacyServiceProvider > &privacyServiceProvider, const PaillierPublicKey &publicKey)
Constructor.
Definition of class Client.
const ServiceProvider::EncryptedUserDataContainer & GetNormalizedScaledRatings() const
Get .
Blinding factor cache parameter container struct.
The public key container structure for the Paillier cryptosystem.
Definition: paillier.h:49