MOTION  0.01
Framework for mixed-protocol multi-party computation
sb_impl.h
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2019 Lennart Braun
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 <algorithm>
28 #include <cassert>
29 #include <cstddef>
30 #include <cstdint>
31 #include <set>
32 #include <type_traits>
33 #include <vector>
34 #include "sp_provider.h"
35 #include "utility/helpers.h"
36 
37 namespace encrypto::motion {
38 
39 namespace detail {
40 
41 // smallest square root of a mod 2^k
42 template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
43 T sqrt(size_t k, T a) {
44  assert(k >= 3);
45  assert(a % 8 == 1);
46 
47  if (a == 1) return 1;
48 
49  std::array<T, 8> roots = {1, 3, 5, 7, 0, 0, 0, 0};
50  std::array<T, 8> new_roots = {0};
51  for (std::size_t j = 4; j < k + 1; ++j) {
52  for (std::size_t l = 0; l < 4; ++l) {
53  T r = roots[l];
54  T i = ((r * r - a) >> (j - 1)) & 1;
55  T nr = (r + (i << (j - 2))) & ((T(1) << j) - 1);
56  new_roots[l] = nr;
57  new_roots[l + 4] = (T(1) << j) - nr;
58  }
59 
60  for (std::size_t l = 0; l < 8; ++l) {
61  T nr = new_roots[l];
62  for (size_t m = 0; m < 8; ++m) {
63  if (roots[m] == 0) {
64  roots[m] = nr;
65  break;
66  } else if (roots[m] == nr) {
67  break;
68  }
69  }
70  }
71  std::swap(roots, new_roots);
72  }
73  T minimum = roots[0];
74  for (std::size_t l = 1; l < 4; ++l) {
75  if (roots[l] < minimum) minimum = roots[l];
76  }
77  return minimum;
78 }
79 
80 // inversion of a mod 2^k
81 template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
82 T invert(std::size_t k, T a) {
83  assert((a & 1) == 1);
84  const T mask = (T(1) << k) - 1;
85  a &= mask;
86  T b = 1;
87  T X;
88  T result = 0;
89  for (std::size_t i = 0; i < k; ++i) {
90  X = b & 1;
91  b = (b - a * X) >> 1;
92  result |= X << i;
93  }
94  return result;
95 }
96 
97 template <typename T>
99 template <>
100 struct get_expanded_type<std::uint8_t> {
101  using type = std::uint16_t;
102 };
103 template <>
104 struct get_expanded_type<std::uint16_t> {
105  using type = std::uint32_t;
106 };
107 template <>
108 struct get_expanded_type<std::uint32_t> {
109  using type = std::uint64_t;
110 };
111 template <>
112 struct get_expanded_type<std::uint64_t> {
113  using type = __uint128_t;
114 };
115 template <typename T>
117 
118 template <typename T>
119 constexpr std::size_t GetBitSize() {
120  return sizeof(T) * 8;
121 }
122 
123 template <typename T, typename U = get_expanded_type_t<T>,
124  typename = std::enable_if_t<std::is_same_v<U, get_expanded_type_t<T>>>>
125 constexpr U GetModMask() {
126  return (U(1) << (GetBitSize<T>() + 2)) - 1;
127 }
128 
129 template <typename T, typename U = get_expanded_type_t<T>,
130  typename = std::enable_if_t<std::is_same_v<U, get_expanded_type_t<T>>>>
131 static std::pair<std::vector<U>, std::vector<U>> compute_sbs_phase_1(std::size_t number_of_sbs,
132  std::size_t my_id,
133  SpVector<U>& sps) {
134  constexpr U mod_mask = GetModMask<T>();
135 
136  // generate random u_i mod 2^k+2
137  auto wb1 = RandomVector<U>(number_of_sbs);
138 
139  // compute a_i = 2 * u_i + 1 mod2^k+2 (for party 0)
140  // a_i = 2 * u_i mod2^k+2 (for all other parties)
141  if (my_id == 0) {
142  std::transform(wb1.cbegin(), wb1.cend(), wb1.begin(),
143  [mod_mask](auto u_i) { return (2 * u_i + 1) & mod_mask; });
144  } else {
145  std::transform(wb1.cbegin(), wb1.cend(), wb1.begin(),
146  [mod_mask](auto u_i) { return (2 * u_i) & mod_mask; });
147  }
148 
149  // start squaring:
150 
151  // mask a with the first part of the SP
152  std::vector<U> wb2; // XXX: maybe reuse SP buffer here?
153  wb2.reserve(number_of_sbs);
154  std::transform(wb1.cbegin(), wb1.cend(), sps.a.cbegin(), std::back_inserter(wb2),
155  [mod_mask](auto a_i, auto sp_a_i) { return (a_i - sp_a_i) & mod_mask; });
156 
157  // wb1 contains our shares of a
158  // wb2 contains our shares of d (which is the masked a)
159  return {wb1, wb2};
160 }
161 
162 template <typename T, typename U = get_expanded_type_t<T>,
163  typename = std::enable_if_t<std::is_same_v<U, get_expanded_type_t<T>>>>
164 static void compute_sbs_phase_2(std::vector<U>& wb1, std::vector<U>& wb2, std::size_t my_id,
165  SpVector<U>& sps) {
166  // wb1 contains our shares of a
167  // wb2 contains the reconstructed d (which is the masked a)
168 
169  constexpr U mod_mask = GetModMask<T>();
170 
171  // continue with squaring:
172  // compute shares of a^2
173  if (my_id == 0) {
174  std::transform(wb1.cbegin(), wb1.cend(), wb2.cbegin(), wb2.begin(),
175  [](auto a, auto d) { return 2 * d * a - d * d; });
176  } else {
177  std::transform(wb1.cbegin(), wb1.cend(), wb2.cbegin(), wb2.begin(),
178  [](auto a, auto d) { return 2 * d * a; });
179  }
180  std::transform(wb2.cbegin(), wb2.cend(), sps.c.cbegin(), wb2.begin(),
181  [mod_mask](auto t, auto c) { return (c + t) & mod_mask; });
182  // wb2 contains now shares of a^2
183 }
184 
185 template <typename T, typename U = get_expanded_type_t<T>,
186  typename = std::enable_if_t<std::is_same_v<U, get_expanded_type_t<T>>>>
187 static void compute_sbs_phase_3(std::vector<U>& wb1, std::vector<U>& wb2, std::vector<T>& sbs,
188  std::size_t my_id) {
189  // sbs is the output buffer
190  // wb1 contains our share of a
191  // wb2 contains the reconstructed a^2
192 
193  constexpr U mod_mask = GetModMask<T>();
194  constexpr U mod_mask_1 = mod_mask >> 1;
195  auto number_of_sbs = wb1.size();
196 
197  // compute c as smallest square root of a^2 mod 2^k+2
198  std::transform(wb2.cbegin(), wb2.cend(), wb2.begin(),
199  [mod_mask](auto asq) { return sqrt(GetBitSize<T>() + 2, U(asq & mod_mask)); });
200 
201  // compute d_i = c^-1 * a + 1 mod 2^k+1 (for party 0)
202  // d_i = c^-1 * a mod 2^k+1 (for all other parties)
203  if (my_id == 0) {
204  std::transform(wb1.cbegin(), wb1.cend(), wb2.cbegin(), wb1.begin(), [](U a_i, U c) {
205  return (invert<U>(GetBitSize<T>() + 1, U(c & mod_mask_1)) * a_i + 1) & mod_mask_1;
206  });
207  } else {
208  std::transform(wb1.cbegin(), wb1.cend(), wb2.cbegin(), wb1.begin(), [](auto a_i, auto c) {
209  return (invert<U>(GetBitSize<T>() + 1, U(c & mod_mask_1)) * a_i) & mod_mask_1;
210  });
211  }
212 
213  // compute b_i = d_i / 2 as element of Z
214  sbs.clear();
215  sbs.reserve(number_of_sbs);
216  std::transform(wb1.cbegin(), wb1.cend(), std::back_inserter(sbs),
217  [](auto& d_i) { return static_cast<T>(d_i >> 1); });
218 }
219 
220 } // namespace detail
221 
222 } // namespace encrypto::motion
helpers.h
encrypto::motion::detail::get_expanded_type< std::uint64_t >::type
__uint128_t type
Definition: sb_impl.h:113
encrypto::motion::detail::compute_sbs_phase_2
static void compute_sbs_phase_2(std::vector< U > &wb1, std::vector< U > &wb2, std::size_t my_id, SpVector< U > &sps)
Definition: sb_impl.h:164
encrypto::motion::SpVector
Definition: sp_provider.h:46
encrypto::motion::SpVector::a
std::vector< T > a
Definition: sp_provider.h:47
encrypto::motion::detail::get_expanded_type< std::uint8_t >::type
std::uint16_t type
Definition: sb_impl.h:101
encrypto::motion::detail::get_expanded_type< std::uint32_t >::type
std::uint64_t type
Definition: sb_impl.h:109
encrypto::motion
Definition: algorithm_description.cpp:35
encrypto::motion::detail::get_expanded_type< std::uint16_t >::type
std::uint32_t type
Definition: sb_impl.h:105
encrypto::motion::detail::get_expanded_type
Definition: sb_impl.h:98
encrypto::motion::detail::compute_sbs_phase_3
static void compute_sbs_phase_3(std::vector< U > &wb1, std::vector< U > &wb2, std::vector< T > &sbs, std::size_t my_id)
Definition: sb_impl.h:187
encrypto::motion::detail::invert
T invert(std::size_t k, T a)
Definition: sb_impl.h:82
encrypto::motion::detail::GetModMask
constexpr U GetModMask()
Definition: sb_impl.h:125
d
static const fe d
Definition: mycurve25519_tables.h:30
encrypto::motion::swap
void swap(ReusablePromise< R, MutexType, ConditionVariableType > &lhs, ReusablePromise< R, MutexType, ConditionVariableType > &rhs) noexcept
Definition: reusable_future.h:270
encrypto::motion::detail::GetBitSize
constexpr std::size_t GetBitSize()
Definition: sb_impl.h:119
encrypto::motion::detail::get_expanded_type_t
typename get_expanded_type< T >::type get_expanded_type_t
Definition: sb_impl.h:116
encrypto::motion::SpVector::c
std::vector< T > c
Definition: sp_provider.h:47
encrypto::motion::detail::sqrt
T sqrt(size_t k, T a)
Definition: sb_impl.h:43
encrypto::motion::detail::compute_sbs_phase_1
static std::pair< std::vector< U >, std::vector< U > > compute_sbs_phase_1(std::size_t number_of_sbs, std::size_t my_id, SpVector< U > &sps)
Definition: sb_impl.h:131
sp_provider.h