block/include/nil/crypto3/detail/inject.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020 Nikita Kaskov <nbering@nil.foundation>
3 // Copyright (c) 2020 Alexander Sokolov <asokolov@nil.foundation>
4 //
5 // MIT License
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 
26 #ifndef CRYPTO3_INJECT_HASH_HPP
27 #define CRYPTO3_INJECT_HASH_HPP
28 
29 #include <nil/crypto3/detail/stream_endian.hpp>
30 #include <nil/crypto3/detail/basic_functions.hpp>
31 #include <nil/crypto3/detail/unbounded_shift.hpp>
32 #include <nil/crypto3/detail/endian_shift.hpp>
33 
34 namespace nil {
35  namespace crypto3 {
36  namespace detail {
37 
38  template<typename Endianness, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
39  struct word_injector;
40 
41  template<int UnitBits, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
42  struct word_injector<stream_endian::big_unit_big_bit<UnitBits>, WordBits, BlockWords, BlockBits>
43  : public basic_functions<WordBits> {
44 
45  constexpr static const std::size_t word_bits = basic_functions<WordBits>::word_bits;
47 
48  typedef std::array<word_type, BlockWords> block_type;
49 
50  static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen) {
51  // Insert word_seen-bit part of word into the block b according to endianness
52 
53  // Check whether we fall out of the block
54  if (block_seen + word_seen <= BlockBits) {
55  std::size_t last_word_ind = block_seen / word_bits;
56  std::size_t last_word_seen = block_seen % word_bits;
57 
58  // Remove garbage
59  w &= high_bits<word_bits>(~word_type(), word_seen);
60  b[last_word_ind] &= high_bits<word_bits>(~word_type(), last_word_seen);
61 
62  // Add significant word bits to block word
63  b[last_word_ind] |= unbounded_shr(w, last_word_seen);
64 
65  // If we fall out of the block word, push the remainder of element to the next block word
66  if (last_word_seen + word_seen > word_bits)
67  b[last_word_ind + 1] = unbounded_shl(w, word_bits - last_word_seen);
68 
69  block_seen += word_seen;
70  }
71  }
72  };
73 
74  template<int UnitBits, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
75  struct word_injector<stream_endian::little_unit_big_bit<UnitBits>, WordBits, BlockWords, BlockBits>
76  : public basic_functions<WordBits> {
77 
78  constexpr static const std::size_t word_bits = basic_functions<WordBits>::word_bits;
80 
81  typedef std::array<word_type, BlockWords> block_type;
82 
83  static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen) {
84  // Insert word_seen-bit part of word into the block b according to endianness
85 
86  // Check whether we fall out of the block
87  if (block_seen + word_seen <= BlockBits) {
88  std::size_t last_word_ind = block_seen / word_bits;
89  std::size_t last_word_seen = block_seen % word_bits;
90 
91  // Remove garbage
92  std::size_t w_rem = word_seen % UnitBits;
93  std::size_t w_unit_bits = word_seen - w_rem;
94  word_type mask =
95  low_bits<word_bits>(~word_type(), w_unit_bits) |
96  unbounded_shl(low_bits<word_bits>(~word_type(), w_rem), w_unit_bits + UnitBits - w_rem);
97  w &= mask;
98 
99  std::size_t b_rem = last_word_seen % UnitBits;
100  std::size_t b_unit_bits = last_word_seen - b_rem;
101  mask = low_bits<word_bits>(~word_type(), b_unit_bits) |
102  unbounded_shl(low_bits<word_bits>(~word_type(), b_rem), b_unit_bits + UnitBits - b_rem);
103  b[last_word_ind] &= mask;
104 
105  // Split and combine parts of unit values
106  std::size_t sz[2] = {UnitBits - b_rem, b_rem};
107  word_type masks[2];
108  masks[0] = unbounded_shl(low_bits<word_bits>(~word_type(), UnitBits - b_rem), b_rem);
109  masks[1] = low_bits<word_bits>(~word_type(), b_rem);
110  std::size_t bw_space = word_bits - last_word_seen;
111  std::size_t w_space = word_seen;
112  word_type w_split = 0;
113  std::size_t sz_ind = 0;
114 
115  while (bw_space && w_space) {
116  w_split |= (!sz_ind ? unbounded_shr(w & masks[0], b_rem) :
117  unbounded_shl(w & masks[1], UnitBits + sz[0]));
118  bw_space -= sz[sz_ind];
119  w_space -= (w_space >= sz[sz_ind]) ? sz[sz_ind] : w_space;
120  masks[sz_ind] = unbounded_shl(masks[sz_ind], UnitBits);
121  sz_ind = 1 - sz_ind;
122  }
123 
124  // Add significant word bits to block word
125  b[last_word_ind] |= unbounded_shl(w_split, b_unit_bits);
126 
127  // If we fall out of the block word, push the remainder of element to the next block word
128  if (last_word_seen + word_seen > word_bits) {
129  w = unbounded_shr(w, word_bits - b_unit_bits - UnitBits);
130  w_split = 0;
131  masks[0] =
132  unbounded_shl(low_bits<word_bits>(~word_type(), UnitBits - b_rem), b_rem + UnitBits);
133  masks[1] = low_bits<word_bits>(~word_type(), b_rem);
134 
135  while (w_space) {
136  w_split |= (!sz_ind ? unbounded_shr(w & masks[0], b_rem) :
137  unbounded_shl(w & masks[1], UnitBits + sz[0]));
138  w_space -= (w_space >= sz[sz_ind]) ? sz[sz_ind] : w_space;
139  masks[sz_ind] = unbounded_shl(masks[sz_ind], UnitBits);
140  sz_ind = 1 - sz_ind;
141  }
142 
143  b[last_word_ind + 1] = unbounded_shr(w_split, UnitBits);
144  }
145 
146  block_seen += word_seen;
147  }
148  }
149  };
150 
151  template<int UnitBits, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
152  struct word_injector<stream_endian::big_unit_little_bit<UnitBits>, WordBits, BlockWords, BlockBits>
153  : public basic_functions<WordBits> {
154 
155  constexpr static const std::size_t word_bits = basic_functions<WordBits>::word_bits;
157 
158  typedef std::array<word_type, BlockWords> block_type;
159 
160  static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen) {
161  // Insert word_seen-bit part of word into the block b according to endianness
162 
163  // Check whether we fall out of the block
164  if (block_seen + word_seen <= BlockBits) {
165  std::size_t last_word_ind = block_seen / word_bits;
166  std::size_t last_word_seen = block_seen % word_bits;
167 
168  // Remove garbage
169  std::size_t w_rem = word_seen % UnitBits;
170  std::size_t w_unit_bits = word_seen - w_rem;
171  word_type mask =
172  high_bits<word_bits>(~word_type(), w_unit_bits) |
173  unbounded_shr(high_bits<word_bits>(~word_type(), w_rem), w_unit_bits + UnitBits - w_rem);
174  w &= mask;
175  std::size_t b_rem = last_word_seen % UnitBits;
176  std::size_t b_unit_bits = last_word_seen - b_rem;
177  mask = high_bits<word_bits>(~word_type(), b_unit_bits) |
178  unbounded_shr(high_bits<word_bits>(~word_type(), b_rem), b_unit_bits + UnitBits - b_rem);
179  b[last_word_ind] &= mask;
180 
181  // Split and combine parts of unit values
182  std::size_t sz[2] = {UnitBits - b_rem, b_rem};
183  word_type masks[2] = {
184  unbounded_shr(high_bits<word_bits>(~word_type(), UnitBits - b_rem), b_rem),
185  high_bits<word_bits>(~word_type(), b_rem)};
186  std::size_t bw_space = word_bits - last_word_seen;
187  std::size_t w_space = word_seen;
188  word_type w_split = 0;
189  std::size_t sz_ind = 0;
190 
191  while (bw_space && w_space) {
192  w_split |= (!sz_ind ? unbounded_shl(w & masks[0], b_rem) :
193  unbounded_shr(w & masks[1], UnitBits + sz[0]));
194  bw_space -= sz[sz_ind];
195  w_space -= (w_space >= sz[sz_ind]) ? sz[sz_ind] : w_space;
196  masks[sz_ind] = unbounded_shr(masks[sz_ind], UnitBits);
197  sz_ind = 1 - sz_ind;
198  }
199 
200  // Add significant word bits to block word
201  b[last_word_ind] |= unbounded_shr(w_split, b_unit_bits);
202 
203  // If we fall out of the block word, push the remainder of element to the next block word
204  if (last_word_seen + word_seen > word_bits) {
205  w = unbounded_shl(w, word_bits - b_unit_bits - UnitBits);
206  w_split = 0;
207  masks[0] =
208  unbounded_shr(high_bits<word_bits>(~word_type(), UnitBits - b_rem), b_rem + UnitBits);
209  masks[1] = high_bits<word_bits>(~word_type(), b_rem);
210 
211  while (w_space) {
212  w_split |= (!sz_ind ? unbounded_shl(w & masks[0], b_rem) :
213  unbounded_shr(w & masks[1], UnitBits + sz[0]));
214  w_space -= (w_space >= sz[sz_ind]) ? sz[sz_ind] : w_space;
215  masks[sz_ind] = unbounded_shr(masks[sz_ind], UnitBits);
216  sz_ind = 1 - sz_ind;
217  }
218 
219  b[last_word_ind + 1] = unbounded_shl(w_split, UnitBits);
220  }
221  block_seen += word_seen;
222  }
223  }
224  };
225 
226  template<int UnitBits, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
227  struct word_injector<stream_endian::little_unit_little_bit<UnitBits>, WordBits, BlockWords, BlockBits>
228  : public basic_functions<WordBits> {
229 
230  constexpr static const std::size_t word_bits = basic_functions<WordBits>::word_bits;
232 
233  typedef std::array<word_type, BlockWords> block_type;
234 
235  static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen) {
236  // Insert word_seen-bit part of word into the block b according to endianness
237 
238  // Check whether we fall out of the block
239  if (block_seen + word_seen <= BlockBits) {
240  std::size_t last_word_ind = block_seen / word_bits;
241  std::size_t last_word_seen = block_seen % word_bits;
242 
243  // Remove garbage
244  w &= low_bits<word_bits>(~word_type(), word_seen);
245  b[last_word_ind] &= low_bits<word_bits>(~word_type(), last_word_seen);
246 
247  // Add significant word bits to block word
248  b[last_word_ind] |= unbounded_shl(w, last_word_seen);
249 
250  // If we fall out of the block word, push the remainder of element to the next block word
251  if (last_word_seen + word_seen > word_bits)
252  b[last_word_ind + 1] = unbounded_shr(w, word_bits - last_word_seen);
253 
254  block_seen += word_seen;
255  }
256  }
257  };
258 
259  template<typename Endianness, std::size_t WordBits, std::size_t BlockWords, std::size_t BlockBits>
260  struct injector : word_injector<Endianness, WordBits, BlockWords, BlockBits> {
261 
262  constexpr static const std::size_t word_bits = basic_functions<WordBits>::word_bits;
264 
265  typedef std::array<word_type, BlockWords> block_type;
266 
267  static void inject(const block_type &b_src, std::size_t b_src_seen, block_type &b_dst,
268  std::size_t &b_dst_seen, std::size_t block_shift = 0) {
269  // Insert word_seen-bit part of word into the block b according to endianness
270 
271  // Check whether we fall out of the block
272  if (b_src_seen + b_dst_seen <= BlockBits) {
273 
274  std::size_t first_word_ind = block_shift / word_bits;
275  std::size_t word_shift = block_shift % word_bits;
276 
277  std::size_t first_word_seen =
278  (word_bits - word_shift) > b_src_seen ? b_src_seen : (word_bits - word_shift);
279 
280  inject(b_src[first_word_ind], first_word_seen, b_dst, b_dst_seen, word_shift);
281 
282  b_src_seen -= first_word_seen;
283 
284  for (std::size_t i = 0; i < (b_src_seen / word_bits); i++) {
285  inject(b_src[first_word_ind + 1 + i], word_bits, b_dst, b_dst_seen);
286  }
287 
288  if (b_src_seen % word_bits) {
289  inject(b_src[first_word_ind + 1 + b_src_seen / word_bits], b_src_seen % word_bits, b_dst,
290  b_dst_seen);
291  }
292  }
293  }
294 
295  static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen,
296  std::size_t word_shift = 0) {
297 
298  word_type word_shifted = w;
299 
300  if (word_shift > 0) {
301  endian_shift<Endianness, word_bits>::to_msb(word_shifted, word_shift);
302  }
303 
305  block_seen);
306  }
307  };
308  } // namespace detail
309  } // namespace crypto3
310 } // namespace nil
311 
312 #endif // CRYPTO3_INJECT_HASH_HPP
T unbounded_shr(T x)
Definition: algebra/include/nil/crypto3/detail/unbounded_shift.hpp:64
T unbounded_shl(T x)
Definition: algebra/include/nil/crypto3/detail/unbounded_shift.hpp:59
Definition: pair.hpp:31
Definition: block/include/nil/crypto3/detail/basic_functions.hpp:37
boost::uint_t< word_bits >::exact word_type
Definition: block/include/nil/crypto3/detail/basic_functions.hpp:42
Definition: block/include/nil/crypto3/detail/endian_shift.hpp:40
Definition: block/include/nil/crypto3/detail/inject.hpp:260
static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen, std::size_t word_shift=0)
Definition: block/include/nil/crypto3/detail/inject.hpp:295
static void inject(const block_type &b_src, std::size_t b_src_seen, block_type &b_dst, std::size_t &b_dst_seen, std::size_t block_shift=0)
Definition: block/include/nil/crypto3/detail/inject.hpp:267
std::array< word_type, BlockWords > block_type
Definition: block/include/nil/crypto3/detail/inject.hpp:265
basic_functions< WordBits >::word_type word_type
Definition: block/include/nil/crypto3/detail/inject.hpp:263
constexpr static const std::size_t word_bits
Definition: block/include/nil/crypto3/detail/inject.hpp:262
static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen)
Definition: block/include/nil/crypto3/detail/inject.hpp:50
std::array< word_type, BlockWords > block_type
Definition: block/include/nil/crypto3/detail/inject.hpp:48
basic_functions< WordBits >::word_type word_type
Definition: block/include/nil/crypto3/detail/inject.hpp:46
static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen)
Definition: block/include/nil/crypto3/detail/inject.hpp:160
std::array< word_type, BlockWords > block_type
Definition: block/include/nil/crypto3/detail/inject.hpp:158
basic_functions< WordBits >::word_type word_type
Definition: block/include/nil/crypto3/detail/inject.hpp:156
basic_functions< WordBits >::word_type word_type
Definition: block/include/nil/crypto3/detail/inject.hpp:79
std::array< word_type, BlockWords > block_type
Definition: block/include/nil/crypto3/detail/inject.hpp:81
static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen)
Definition: block/include/nil/crypto3/detail/inject.hpp:83
std::array< word_type, BlockWords > block_type
Definition: block/include/nil/crypto3/detail/inject.hpp:233
basic_functions< WordBits >::word_type word_type
Definition: block/include/nil/crypto3/detail/inject.hpp:231
static void inject(word_type w, std::size_t word_seen, block_type &b, std::size_t &block_seen)
Definition: block/include/nil/crypto3/detail/inject.hpp:235
Definition: block/include/nil/crypto3/detail/inject.hpp:39