MOTION  0.01
Framework for mixed-protocol multi-party computation
helpers.h
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2019 Oleksandr Tkachenko
4 // Cryptography and Privacy Engineering Group (ENCRYPTO)
5 // TU Darmstadt, Germany
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 
25 #pragma once
26 
27 #include <flatbuffers/flatbuffers.h>
28 #include <fmt/format.h>
29 #include <random>
30 
31 #include "condition.h"
33 #include "typedefs.h"
34 
35 namespace encrypto::motion {
36 
40 template <typename UnsignedIntegralType,
41  typename = std::enable_if_t<std::is_unsigned_v<UnsignedIntegralType>>>
42 std::vector<UnsignedIntegralType> RandomVector(std::size_t length) {
43  const auto byte_size = sizeof(UnsignedIntegralType) * length;
44  std::vector<UnsignedIntegralType> vec(length);
45 
46  auto& rng = DefaultRng::GetThreadInstance();
47  rng.RandomBytes(reinterpret_cast<std::byte*>(vec.data()), byte_size);
48 
49  return vec;
50 }
51 
55 template <typename UnsignedIntegralType,
56  typename = std::enable_if_t<std::is_unsigned_v<UnsignedIntegralType>>>
57 inline std::vector<std::uint8_t> ToByteVector(const std::vector<UnsignedIntegralType>& values) {
58  std::vector<std::uint8_t> result(reinterpret_cast<const std::uint8_t*>(values.data()),
59  reinterpret_cast<const std::uint8_t*>(values.data()) +
60  sizeof(UnsignedIntegralType) * values.size());
61  return result;
62 }
63 
67 template <typename UnsignedIntegralType,
68  typename = std::enable_if_t<std::is_unsigned_v<UnsignedIntegralType>>>
69 inline std::vector<UnsignedIntegralType> FromByteVector(const std::vector<std::uint8_t>& buffer) {
70  assert(buffer.size() % sizeof(UnsignedIntegralType) ==
71  0); // buffer length is multiple of the element size
72  std::vector<UnsignedIntegralType> result(sizeof(UnsignedIntegralType) * buffer.size());
73  std::copy(buffer.data(), buffer.data() + buffer.size(),
74  reinterpret_cast<std::uint8_t*>(result.data()));
75  return result;
76 }
77 
81 template <typename UnsignedIntegralType,
82  typename = std::enable_if_t<std::is_unsigned_v<UnsignedIntegralType>>>
83 inline std::vector<UnsignedIntegralType> FromByteVector(
84  const flatbuffers::Vector<std::uint8_t>& buffer) {
85  assert(buffer.size() % sizeof(UnsignedIntegralType) ==
86  0); // buffer length is multiple of the element size
87  std::vector<UnsignedIntegralType> result(buffer.size() / sizeof(UnsignedIntegralType));
88  std::copy(buffer.data(), buffer.data() + buffer.size(),
89  reinterpret_cast<std::uint8_t*>(result.data()));
90  return result;
91 }
92 
99 template <typename T>
100 inline std::vector<T> AddVectors(const std::vector<T>& a, const std::vector<T>& b) {
101  assert(a.size() == b.size());
102  if (a.size() == 0) {
103  return {};
104  } // if empty input vector
105  std::vector<T> result = a;
106 #pragma omp simd
107  for (auto j = 0ull; j < result.size(); ++j) {
108  result.at(j) += b.at(j); // TODO: implement using AVX2 and AVX512
109  }
110  return result;
111 }
112 
119 template <typename T>
120 inline std::vector<T> SubVectors(const std::vector<T>& a, const std::vector<T>& b) {
121  assert(a.size() == b.size());
122  if (a.size() == 0) {
123  return {};
124  } // if empty input vector
125  std::vector<T> result = a;
126  for (auto j = 0ull; j < result.size(); ++j) {
127  result.at(j) -= b.at(j); // TODO: implement using AVX2 and AVX512
128  }
129  return result;
130 }
131 
138 template <typename T>
139 inline std::vector<T> MultiplyVectors(std::vector<T> a, std::vector<T> b) {
140  assert(a.size() == b.size());
141  if (a.size() == 0) {
142  return {};
143  } // if empty input vector
144  std::vector<T> result = a;
145 
146  for (auto j = 0ull; j < result.size(); ++j) {
147  result.at(j) *= b.at(j); // TODO: implement using AVX2 and AVX512
148  }
149  return result;
150 }
151 
158 template <typename T>
159 inline std::vector<T> AddVectors(std::vector<std::vector<T>>& vectors) {
160  if (vectors.size() == 0) {
161  return {};
162  } // if empty input vector
163 
164  std::vector<T> result = vectors.at(0);
165 
166  for (auto i = 1ull; i < vectors.size(); ++i) {
167  auto& inner_vector = vectors.at(i);
168  assert(inner_vector.size() == result.size()); // expect the vectors to be of the same size
169  for (auto j = 0ull; j < result.size(); ++j) {
170  result.at(j) += inner_vector.at(j); // TODO: implement using AVX2 and AVX512
171  }
172  }
173  return result;
174 }
175 
182 template <typename T>
183 inline std::vector<T> AddVectors(std::vector<std::vector<T>>&& vectors) {
184  return AddVectors(vectors);
185 }
186 
187 // XXX two distinct vectors do not overlop, so I don't see the use for the restrict functions.
188 
196 template <typename T>
197 inline std::vector<T> RestrictAddVectors(const std::vector<T>& a, const std::vector<T>& b) {
198  assert(a.size() == b.size());
199  if (a.size() == 0) {
200  return {};
201  } // if empty input vector
202  std::vector<T> result(a.size());
203  const T* __restrict__ a_pointer{a.data()};
204  const T* __restrict__ b_pointer{b.data()};
205  T* __restrict__ result_pointer{result.data()};
206  std::transform(a_pointer, a_pointer + a.size(), b_pointer, result_pointer,
207  [](const T& a_value, const T& b_value) { return a_value + b_value; });
208  return result;
209 }
210 
218 template <typename T>
219 inline std::vector<T> RestrictSubVectors(const std::vector<T>& a, const std::vector<T>& b) {
220  assert(a.size() == b.size());
221  if (a.size() == 0) {
222  return {};
223  } // if empty input vector
224  std::vector<T> result(a.size());
225  const T* __restrict__ a_pointer{a.data()};
226  const T* __restrict__ b_pointer{b.data()};
227  T* __restrict__ result_pointer{result.data()};
228  std::transform(a_pointer, a_pointer + a.size(), b_pointer, result_pointer,
229  [](const T& a_value, const T& b_value) { return a_value - b_value; });
230  return result;
231 }
232 
240 template <typename T>
241 inline std::vector<T> RestrictMulVectors(const std::vector<T>& a, const std::vector<T>& b) {
242  assert(a.size() == b.size());
243  if (a.size() == 0) {
244  return {};
245  } // if empty input vector
246  std::vector<T> result(a.size());
247  const T* __restrict__ a_pointer{a.data()};
248  const T* __restrict__ b_pointer{b.data()};
249  T* __restrict__ result_pointer{result.data()};
250  std::transform(a_pointer, a_pointer + a.size(), b_pointer, result_pointer,
251  [](const T& a_value, const T& b_value) { return a_value * b_value; });
252  return result;
253 }
254 
258 template <typename T>
259 inline T SumReduction(const std::vector<T>& values) {
260  if (values.size() == 0) {
261  return 0;
262  } else if (values.size() == 1) {
263  return values.at(0);
264  } else {
265  T sum = 0;
266 #pragma omp parallel for reduction(+ : sum) default(none) shared(values)
267  for (auto i = 0ull; i < values.size(); ++i) {
268  sum += values.at(i);
269  }
270  return sum;
271  }
272 }
273 
277 template <typename T>
278 inline T SubReduction(const std::vector<T>& values) {
279  if (values.size() == 0) {
280  return 0;
281  } else {
282  T result = values.at(0);
283  for (auto i = 1ull; i < values.size(); ++i) {
284  result -= values.at(i);
285  }
286  return result;
287  }
288 }
289 
293 template <typename T>
294 inline T MulReduction(const std::vector<T>& values) {
295  if (values.size() == 0) {
296  return 0;
297  } else {
298  T product = values.at(0);
299  for (auto i = 1ull; i < values.size(); ++i) {
300  product *= values.at(i);
301  }
302  return product;
303  }
304 }
305 
316 template <typename T>
317 inline std::vector<T> RowSumReduction(const std::vector<std::vector<T>>& values) {
318  if (values.size() == 0) {
319  return {};
320  } else {
321  std::vector<T> sum(values.at(0).size());
322  for (auto i = 1ull; i < values.size(); ++i) {
323  assert(values.at(0).size() == values.at(i).size());
324  }
325 
326  for (auto i = 0ull; i < sum.size(); ++i) {
327  for (auto j = 0ull; j < values.size(); ++j) {
328  sum.at(i) += values.at(j).at(i);
329  }
330  }
331  return std::move(sum);
332  }
333 }
334 
345 template <typename T>
346 inline std::vector<T> RowSubReduction(const std::vector<std::vector<T>>& values) {
347  if (values.size() == 0) {
348  return {};
349  } else {
350  std::vector<T> result = values.at(0);
351  for (auto i = 1ull; i < values.size(); ++i) {
352  assert(values.at(0).size() == values.at(i).size());
353  }
354 
355  for (auto i = 0ull; i < result.size(); ++i) {
356  for (auto j = 1ull; j < values.size(); ++j) {
357  result.at(i) -= values.at(j).at(i);
358  }
359  }
360  return std::move(result);
361  }
362 }
363 
374 template <typename T>
375 inline std::vector<T> RowMulReduction(const std::vector<std::vector<T>>& values) {
376  if (values.size() == 0) {
377  return {};
378  } else {
379  std::vector<T> product(values.at(0).size(), 1);
380  for (auto i = 1ull; i < values.size(); ++i) {
381  assert(values.at(0).size() == values.at(i).size());
382  }
383 
384  for (auto i = 0ull; i < product.size(); ++i) {
385  for (auto j = 0ull; j < values.size(); ++j) {
386  product.at(i) *= values.at(j).at(i);
387  }
388  }
389  return std::move(product);
390  }
391 }
392 
396 template <typename UnsignedIntegralType,
397  typename = std::enable_if_t<std::is_unsigned_v<UnsignedIntegralType>>>
398 bool IsPowerOfTwo(UnsignedIntegralType x) {
399  return x > 0 && (!(x & (x - 1)));
400 }
401 
405 inline std::string Hex(const std::uint8_t* values, std::size_t n) {
406  std::string buffer;
407  for (auto i = 0ull; i < n; ++i) {
408  buffer.append(fmt::format("{0:#x} ", values[i]));
409  }
410  buffer.erase(buffer.end() - 1); // remove the last whitespace
411  return buffer;
412 }
413 
417 inline std::string Hex(const std::byte* values, std::size_t n) {
418  return Hex(reinterpret_cast<const std::uint8_t*>(values), n);
419 }
420 
423 template <std::size_t N>
424 inline std::string Hex(const std::array<std::byte, N>& values) {
425  return Hex(reinterpret_cast<const std::uint8_t*>(values.data()), values.size());
426 }
427 
430 template <std::size_t N>
431 inline std::string Hex(const std::array<std::uint8_t, N>& values) {
432  return Hex(values.data(), values.size());
433 }
434 
437 inline std::string Hex(const std::vector<std::uint8_t>& values) {
438  return Hex(values.data(), values.size());
439 }
440 
443 inline std::string Hex(const std::vector<std::byte>& values) {
444  return Hex(values.data(), values.size());
445 }
446 
449 inline std::string Hex(const std::vector<std::uint8_t>&& values) { return Hex(values); }
450 
454 template <typename T>
455 inline std::string to_string(std::vector<T> values) {
456  using std::to_string;
457  std::string result;
458  for (auto& v : values) {
459  result.append(to_string(v) + " ");
460  }
461  return result;
462 }
463 
465 
466 template <typename T>
467 inline bool Vectors(const std::vector<T>& a, const std::vector<T>& b) {
468  if (a.size() != b.size()) {
469  return false;
470  }
471  for (auto i = 0ull; i < a.size(); ++i) {
472  if (a.at(i) != b.at(i)) {
473  return false;
474  }
475  }
476  return true;
477 }
478 
481 template <typename T>
482 inline bool Dimensions(const std::vector<std::vector<T>>& values) {
483  if (values.size() <= 1) {
484  return true;
485  } else {
486  auto first_size = values.at(0).size();
487  for (auto i = 1ull; i < values.size(); ++i) {
488  if (first_size != values.at(i).size()) {
489  return false;
490  }
491  }
492  }
493  return true;
494 }
495 
500 std::size_t DivideAndCeil(std::size_t dividend, std::size_t divisor);
501 
504 constexpr std::size_t BitsToBytes(const std::size_t bits) { return (bits + 7) / 8; }
505 
506 } // namespace encrypto::motion
to_string
std::string to_string(Provider p)
Definition: benchmark_providers.h:44
condition.h
encrypto::motion::RandomVector
std::vector< UnsignedIntegralType > RandomVector(std::size_t length)
Returns a vector of length random unsigned integral values.
Definition: helpers.h:42
helpers.h
encrypto::motion::RestrictMulVectors
std::vector< T > RestrictMulVectors(const std::vector< T > &a, const std::vector< T > &b)
Mulitiplies each element in a and b and returns the result. It is assumed that the vectors do not ove...
Definition: helpers.h:241
encrypto::motion::MultiplyVectors
std::vector< T > MultiplyVectors(std::vector< T > a, std::vector< T > b)
Multiplies each element in a and b and returns the result.
Definition: helpers.h:139
encrypto::motion::SumReduction
T SumReduction(const std::vector< T > &values)
Returns the sum of each element in values.
Definition: helpers.h:259
encrypto::motion::FromByteVector
std::vector< UnsignedIntegralType > FromByteVector(const std::vector< std::uint8_t > &buffer)
Converts a vector of uint8_t to a vector of unsigned integral values.
Definition: helpers.h:69
encrypto::motion::BitsToBytes
constexpr std::size_t BitsToBytes(const std::size_t bits)
Returns the number of bytes necessary to store bits bits.
Definition: helpers.h:504
encrypto::motion::AddVectors
std::vector< T > AddVectors(const std::vector< T > &a, const std::vector< T > &b)
Adds each element in a and b and returns the result.
Definition: helpers.h:100
encrypto::motion::SubReduction
T SubReduction(const std::vector< T > &values)
Returns the difference of each element in values.
Definition: helpers.h:278
encrypto::motion::Aes128CtrRng::GetThreadInstance
static Aes128CtrRng & GetThreadInstance()
Definition: aes128_ctr_rng.h:56
encrypto::motion::RestrictSubVectors
std::vector< T > RestrictSubVectors(const std::vector< T > &a, const std::vector< T > &b)
Subtracts each element in a and b and returns the result. It is assumed that the vectors do not overl...
Definition: helpers.h:219
encrypto::motion::DivideAndCeil
std::size_t DivideAndCeil(std::size_t dividend, std::size_t divisor)
Divides two size_t and returns the ceiled quotient.
Definition: helpers.cpp:34
encrypto::motion::RestrictAddVectors
std::vector< T > RestrictAddVectors(const std::vector< T > &a, const std::vector< T > &b)
Adds each element in a and b and returns the result. It is assumed that the vectors do not overlap.
Definition: helpers.h:197
encrypto::motion::Hex
std::string Hex(const std::uint8_t *values, std::size_t n)
Returns a hexadecimal string representation of the bytes stored in values.
Definition: helpers.h:405
encrypto::motion::RowMulReduction
std::vector< T > RowMulReduction(const std::vector< std::vector< T >> &values)
Returns the product of each row in a matrix.
Definition: helpers.h:375
encrypto::motion
Definition: algorithm_description.cpp:35
encrypto::motion::ToByteVector
std::vector< std::uint8_t > ToByteVector(const std::vector< UnsignedIntegralType > &values)
Converts a vector of unsigned integral values to a vector of uint8_t.
Definition: helpers.h:57
encrypto::motion::IsPowerOfTwo
bool IsPowerOfTwo(UnsignedIntegralType x)
Check if unisgned integral value is a power of two.
Definition: helpers.h:398
typedefs.h
encrypto::motion::Dimensions
bool Dimensions(const std::vector< std::vector< T >> &values)
Checks if all the vectors have the same size.
Definition: helpers.h:482
encrypto::motion::RowSumReduction
std::vector< T > RowSumReduction(const std::vector< std::vector< T >> &values)
Returns the sum of each row in a matrix.
Definition: helpers.h:317
encrypto::motion::RowSubReduction
std::vector< T > RowSubReduction(const std::vector< std::vector< T >> &values)
Returns the difference of each row in a matrix.
Definition: helpers.h:346
encrypto::motion::SubVectors
std::vector< T > SubVectors(const std::vector< T > &a, const std::vector< T > &b)
Subtracts each element in a and b and returns the result.
Definition: helpers.h:120
default_rng.h
encrypto::motion::MulReduction
T MulReduction(const std::vector< T > &values)
Returns the product of each element in values.
Definition: helpers.h:294
encrypto::motion::to_string
std::string to_string(std::vector< T > values)
Returns a string representation of the std::vector values.
Definition: helpers.h:455
encrypto::motion::Vectors
bool Vectors(const std::vector< T > &a, const std::vector< T > &b)
XXX the std library implements operators for vector comparisions.
Definition: helpers.h:467