HEBench
original_flow_palisade.cpp
Go to the documentation of this file.
1 
2 // Copyright (C) 2021 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
8 #include <cassert>
9 #include <cstdint>
10 #include <iostream>
11 #include <memory>
12 #include <random>
13 #include <stdexcept>
14 
15 #include "palisade.h"
16 
17 class Workload
18 {
19 public:
20  Workload(std::size_t vector_size);
21 
22  std::vector<lbcrypto::Plaintext> encodeVector(const std::vector<std::vector<std::int64_t>> &vec);
23  std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> encryptVector(const std::vector<lbcrypto::Plaintext> &encoded_vec);
24  std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> eltwiseadd(const std::vector<lbcrypto::Plaintext> &A,
25  const std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> &B);
26  std::vector<lbcrypto::Plaintext> decryptResult(const std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> &encrypted_result);
27  std::vector<std::vector<int64_t>> decodeResult(const std::vector<lbcrypto::Plaintext> &encoded_result);
28 
29 private:
30  class PalisadeBFVContext
31  {
32  public:
33  PalisadeBFVContext(int poly_modulus_degree)
34  {
35  std::size_t plaintext_modulus = 65537;
36  lbcrypto::SecurityLevel sec_level = lbcrypto::HEStd_128_classic;
37  double sigma = 3.2;
38  std::size_t num_coeff_moduli = 2;
39  std::size_t max_depth = 2;
40  std::size_t coeff_moduli_bits = 40;
41 
42  lbcrypto::CryptoContext<lbcrypto::DCRTPoly> crypto_context =
43  lbcrypto::CryptoContextFactory<lbcrypto::DCRTPoly>::genCryptoContextBFVrns(
44  plaintext_modulus, sec_level, sigma, 0, num_coeff_moduli,
45  0, OPTIMIZED, max_depth, 0, coeff_moduli_bits, poly_modulus_degree);
46  crypto_context->Enable(ENCRYPTION);
47  crypto_context->Enable(SHE);
48 
49  lbcrypto::LPKeyPair<lbcrypto::DCRTPoly> local_key = crypto_context->KeyGen();
50  lbcrypto::LPKeyPair<lbcrypto::DCRTPoly> *p_key = new lbcrypto::LPKeyPair<lbcrypto::DCRTPoly>(local_key.publicKey, local_key.secretKey);
51  local_key = lbcrypto::LPKeyPair<lbcrypto::DCRTPoly>();
52  m_keys = std::unique_ptr<lbcrypto::LPKeyPair<lbcrypto::DCRTPoly>>(p_key);
53 
54  m_p_palisade_context = std::make_shared<lbcrypto::CryptoContext<lbcrypto::DCRTPoly>>(crypto_context);
55  m_slot_count = poly_modulus_degree;
56  }
57 
58  auto publicKey() const { return m_keys->publicKey; }
59  std::size_t getSlotCount() const { return m_slot_count; }
60  lbcrypto::CryptoContext<lbcrypto::DCRTPoly> &context() { return *m_p_palisade_context; }
61  void decrypt(const lbcrypto::Ciphertext<lbcrypto::DCRTPoly> &cipher, lbcrypto::Plaintext &plain)
62  {
63  context()->Decrypt(m_keys->secretKey, cipher, &plain);
64  }
65 
66  lbcrypto::Plaintext decrypt(const lbcrypto::Ciphertext<lbcrypto::DCRTPoly> &cipher)
67  {
68  lbcrypto::Plaintext retval;
69  decrypt(cipher, retval);
70  return retval;
71  }
72 
73  private:
74  std::shared_ptr<lbcrypto::CryptoContext<lbcrypto::DCRTPoly>> m_p_palisade_context;
75  std::unique_ptr<lbcrypto::LPKeyPair<lbcrypto::DCRTPoly>> m_keys;
76  std::size_t m_slot_count;
77  };
78 
79  std::size_t m_vector_size;
80  std::shared_ptr<PalisadeBFVContext> m_p_context;
81 
82  PalisadeBFVContext &context() { return *m_p_context; }
83 };
84 
85 Workload::Workload(std::size_t vector_size)
86 {
87  if (vector_size <= 0)
88  throw std::invalid_argument("vector_size");
89  m_vector_size = vector_size;
90  m_p_context = std::make_shared<PalisadeBFVContext>(8192);
91 }
92 
93 std::vector<lbcrypto::Plaintext> Workload::encodeVector(const std::vector<std::vector<std::int64_t>> &vec)
94 {
95  std::vector<lbcrypto::Plaintext> retval(vec.size());
96 
97  for (std::size_t i = 0; i < vec.size(); ++i)
98  {
99  assert(vec[i].size() <= context().getSlotCount());
100  retval[i] = context().context()->MakePackedPlaintext(vec[i]);
101  }
102  return retval;
103 }
104 
105 std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> Workload::encryptVector(const std::vector<lbcrypto::Plaintext> &encoded_vec)
106 {
107  std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> retval(encoded_vec.size());
108  for (std::size_t i = 0; i < encoded_vec.size(); i++)
109  retval[i] = context().context()->Encrypt(context().publicKey(), encoded_vec[i]);
110  return retval;
111 }
112 
113 std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> Workload::eltwiseadd(const std::vector<lbcrypto::Plaintext> &A,
114  const std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> &B)
115 {
116  std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> retval(A.size() * B.size());
117 
118  // This is the main operation function:
119  // for an offline test, it must store the result of the operation on every
120  // set of input sample in the same order as the input set.
121  // See documentation on "Ordering of Results Based on Input Batch Sizes"
122  // for details.
123  for (std::size_t A_i = 0; A_i < A.size(); ++A_i)
124  for (std::size_t B_i = 0; B_i < B.size(); ++B_i)
125  {
126  lbcrypto::Ciphertext<lbcrypto::DCRTPoly> &retval_item = retval[A_i * B.size() + B_i];
127  retval_item = context().context()->EvalAdd(B[B_i], A[A_i]);
128  }
129 
130  return retval;
131 }
132 
133 std::vector<lbcrypto::Plaintext> Workload::decryptResult(const std::vector<lbcrypto::Ciphertext<lbcrypto::DCRTPoly>> &encrypted_result)
134 {
135  std::vector<lbcrypto::Plaintext> retval(encrypted_result.size());
136  for (std::size_t i = 0; i < encrypted_result.size(); i++)
137  retval[i] = context().decrypt(encrypted_result[i]);
138  return retval;
139 }
140 
141 std::vector<std::vector<int64_t>> Workload::decodeResult(const std::vector<lbcrypto::Plaintext> &encoded_result)
142 {
143  std::vector<std::vector<int64_t>> retval(encoded_result.size());
144  for (std::size_t i = 0; i < encoded_result.size(); ++i)
145  {
146  retval[i] = encoded_result[i]->GetPackedValue();
147  retval[i].resize(m_vector_size);
148  }
149  return retval;
150 }
151 
152 //---------------------------------------------------------------------
153 // main() implementation tests the workflow
154 
155 int main()
156 {
157  static const std::size_t VectorSize = 400;
158  static const std::size_t DimensionA = 2;
159  static const std::size_t DimensionB = 5;
160 
161  // START data prep
162  std::vector<std::vector<std::int64_t>> A(DimensionA, std::vector<std::int64_t>(VectorSize));
163  std::vector<std::vector<std::int64_t>> B(DimensionB, std::vector<std::int64_t>(VectorSize));
164 
165  // generate and fill vectors with random data
166  std::random_device rd;
167  std::mt19937 gen(rd());
168  std::uniform_int_distribution<> distrib(-100, 100);
169 
170  for (std::size_t i = 0; i < A.size(); ++i)
171  for (std::size_t j = 0; j < A[i].size(); ++j)
172  A[i][j] = distrib(gen);
173  for (std::size_t i = 0; i < B.size(); ++i)
174  for (std::size_t j = 0; j < B[i].size(); ++j)
175  B[i][j] = distrib(gen);
176  // END data prep
177 
178  //---------------------------------------------------------------------
179 
180  // START Backend
181  std::shared_ptr<Workload> p_workload = // initialize
182  std::make_shared<Workload>(VectorSize);
183  Workload &workload = *p_workload;
184  // For illustration purposes only: all functions in the pipeline should
185  // be able to be nested with each other in the proper order.
186  std::vector<std::vector<std::int64_t>> result =
187  workload.decodeResult(
188  workload.decryptResult(
189  workload.eltwiseadd(workload.encodeVector(A),
190  workload.encryptVector(workload.encodeVector(B)))));
191  p_workload.reset(); // terminate
192  // END Backend
193 
194  //---------------------------------------------------------------------
195 
196  // START Validation
197 
198  std::vector<std::vector<std::int64_t>> exp_out(DimensionA * DimensionB, std::vector<std::int64_t>(VectorSize));
199  assert(exp_out.size() == result.size());
200 
201  // compute ground truth
202  std::size_t result_i = 0;
203  for (std::size_t A_i = 0; A_i < A.size(); ++A_i)
204  for (std::size_t B_i = 0; B_i < B.size(); ++B_i)
205  {
206  for (std::size_t i = 0; i < VectorSize; ++i)
207  exp_out[result_i][i] = A[A_i][i] + B[B_i][i];
208  ++result_i;
209  }
210 
211  if (result == exp_out)
212  std::cout << "OK" << std::endl;
213  else
214  std::cout << "Fail" << std::endl;
215  // END Validation
216 
217  return 0;
218 }
219 
ErrorCode decrypt(Handle h_benchmark, Handle h_ciphertext, Handle *h_plaintext)
Decrypts a cipher text into corresponding plain text.
Workload
Defines all possible workloads.
Definition: types.h:83
int main(int argc, char **argv)