MCKL
Monte Carlo Kernel Library
skein.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/skein.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_RANDOM_SKEIN_HPP
33 #define MCKL_RANDOM_SKEIN_HPP
34 
36 #include <mckl/random/threefry.hpp>
37 
38 MCKL_PUSH_CLANG_WARNING("-Wpadded")
39 
40 namespace mckl {
41 
44 template <typename Generator>
45 class Skein
46 {
47  public:
49  using key_type = typename Generator::key_type;
50 
52  using value_type = typename key_type::value_type;
53 
55  class type_field
56  {
57  public:
59  static constexpr int key() { return 0; }
60 
62  static constexpr int cfg() { return 4; }
63 
65  static constexpr int prs() { return 8; }
66 
68  static constexpr int pub() { return 12; }
69 
71  static constexpr int kdf() { return 16; }
72 
74  static constexpr int non() { return 20; }
75 
77  static constexpr int msg() { return 48; }
78 
80  static constexpr int out() { return 63; }
81  }; // class type
82 
84  class param_type
85  {
86  public:
92  explicit param_type(std::size_t N = 0, const void *data = nullptr,
93  int type = type_field::msg())
94  : N_(N), data_(static_cast<const char *>(data)), type_(type & 0x3F)
95  {
96  }
97 
99  std::size_t bits() const { return N_; }
100 
102  std::size_t bytes() const
103  {
104  return N_ / CHAR_BIT + (N_ % CHAR_BIT == 0 ? 0 : 1);
105  }
106 
108  const char *data() const { return data_; }
109 
111  int type() const { return type_; }
112 
113  private:
114  std::size_t N_;
115  const char *data_;
116  int type_;
117  }; // class param_type
118 
121  {
122  public:
126 
128  {
129  private:
130  key_type G_;
131  int type_;
132 
133  friend mono_hasher;
134  }; // class state_type
135 
136  explicit mono_hasher(std::size_t N, const param_type &K = param_type())
137  : N_(N), K_(K), C_(configure(N_, 0, 0, 0))
138  {
139  internal::union_le<char>(C_);
140  }
141 
142  state_type init() const
143  {
144  state_type ret;
145  std::memset(&ret, 0, sizeof(ret));
146 
147  value_type t1 = 0;
148  if (K_.bits() != 0) {
149  set_type(t1, type_field::key());
150  ret.G_ = ubi(ret.G_, K_, 0, t1);
151  }
152 
153  set_type(t1, type_field::cfg());
154  ret.G_ = ubi(ret.G_, param_type(256, C_.data()), 0, t1);
155 
156  return ret;
157  }
158 
159  void update(state_type &state, const param_type &M) const
160  {
161  if (state.type_ == 0) {
162  runtime_assert(M.type() > type_field::cfg(),
163  "**Skein::hash** M[0].type() <= type_field::cfg()");
164  } else {
165  runtime_assert(M.type() > state.type_,
166  "**Skein::hash** M[i].type() <= M[i - 1].type()");
167  }
168 
169  value_type t1 = 0;
170  set_type(t1, M.type());
171  state.G_ = ubi(state.G_, M, 0, t1);
172  state.type_ = M.type();
173  }
174 
175  void output(const state_type &state, void *H) const
176  {
177  runtime_assert(state.type_ < type_field::out(),
178  "**Skein::hash** M[n - 1].type() >= type_field::out()");
179 
180  Skein::output(state.G_, N_, H);
181  }
182 
183  private:
184  std::size_t N_;
185  param_type K_;
186  std::array<std::uint64_t, 4> C_;
187  }; // class mono_hasher
188 
190  {
191  public:
195 
197  {
198  private:
199  key_type G_;
200  value_type t0_;
201  Vector<key_type> M1_;
202 
203  friend tree_hasher;
204  }; // class state_type
205 
206  explicit tree_hasher(std::size_t N, const param_type &K = param_type(),
207  int Yl = 20, int Yf = 20, int Ym = 2)
208  : N_(N)
209  , K_(K)
210  , Yl_(Yl & 0xFF)
211  , Yf_(Yf & 0xFF)
212  , Ym_(Ym & 0xFF)
213  , C_(configure(N_, Yl_, Yf_, Ym_))
214  {
215  internal::union_le<char>(C_);
216  }
217 
218  state_type init() const
219  {
220  state_type ret;
221  std::memset(&ret, 0, sizeof(key_type) + sizeof(value_type));
222 
223  value_type t1 = 0;
224 
225  if (K_.bits() != 0) {
226  set_type(t1, type_field::key());
227  ret.G_ = ubi(ret.G_, K_, 0, t1);
228  }
229 
230  set_type(t1, type_field::cfg());
231  ret.G_ = ubi(ret.G_, param_type(256, C_.data()), 0, t1);
232 
233  return ret;
234  }
235 
236  void update(state_type &state, const param_type &M) const
237  {
238  runtime_assert(M.type() == type_field::msg(),
239  "**Skein::hash** M[i].type() != type_field::msg()");
240 
241  ubi_tree_m1(state.G_, M, Yl_, state.M1_, state.t0_);
242  }
243 
244  void output(state_type &state, void *H) const
245  {
246  state.G_ = ubi_tree(state.G_, Yl_, Yf_, Ym_, 1, state.M1_);
247  Skein::output(state.G_, N_, H);
248  }
249 
250  private:
251  std::size_t N_;
252  param_type K_;
253  int Yl_;
254  int Yf_;
255  int Ym_;
256  std::array<std::uint64_t, 4> C_;
257  }; // class tree_hasher
258 
260  static constexpr std::size_t bytes() { return sizeof(key_type); }
261 
263  static constexpr std::size_t bits() { return sizeof(key_type) * CHAR_BIT; }
264 
269  static void hash(const param_type &M, std::size_t N, void *H)
270  {
271  hash(1, &M, N, H);
272  }
273 
291  static void hash(std::size_t n, const param_type *M, std::size_t N,
292  void *H, const param_type &K = param_type(), int Yl = 0, int Yf = 0,
293  int Ym = 0)
294  {
295  if ((Yl | Yf | Ym) == 0) {
296  mono_hasher hasher(N, K);
297  auto state = hasher.init();
298  for (std::size_t i = 0; i != n; ++i) {
299  hasher.update(state, M[i]);
300  }
301  hasher.output(state, H);
302  } else {
303  tree_hasher hasher(N, K, Yl, Yf, Ym);
304  auto state = hasher.init();
305  for (std::size_t i = 0; i != n; ++i) {
306  hasher.update(state, M[i]);
307  }
308  hasher.output(state, H);
309  }
310  }
311 
312  private:
313  static_assert(bits() >= 64,
314  "**Skein** used with a Generator with less than 64 bits");
315 
316  static_assert(std::is_unsigned<value_type>::value,
317  "**Skein** used with a Generator with key_type::value_type not an "
318  "unsigned integer type");
319 
320  static_assert(std::numeric_limits<value_type>::digits >= 32,
321  "**Skein** used with a Generator with key_type::value_type less than "
322  "32 bits");
323 
324  static_assert(sizeof(key_type) == Generator::size(),
325  "**Skein** used with a Generator with block and key different in "
326  "size");
327 
328  static key_type ubi(
329  const key_type &G, const param_type &M, value_type t0, value_type t1)
330  {
331  std::size_t N = M.bits();
332  const char *C = M.data();
333  const std::size_t k = internal::BufferSize<key_type>::value;
334  alignas(MCKL_ALIGNMENT) std::array<key_type, k> message;
335 
336  const bool B = N % CHAR_BIT != 0;
337  key_type H = G;
338 
339  // Process the only block
340  if (N <= bits()) {
341  get_block(t0, C, message[0], N);
342  set_flags(t1, true, true, B);
343  enc_block(H, message[0], t0, t1);
344 
345  return H;
346  }
347 
348  // Process the first block
349  set_flags(t1, true, false, B);
350  get_block(t0, C, message[0]);
351  enc_block(H, message[0], t0, t1);
352  N -= bits();
353  C += bytes();
354 
355  // Process the second and the last block
356  if (N <= bits()) {
357  get_block(t0, C, message[0], N);
358  set_flags(t1, false, true, B);
359  enc_block(H, message[0], t0, t1);
360 
361  return H;
362  }
363 
364  // Process the intermediate blocks
365  set_flags(t1, false, false, B);
366  const std::size_t n = N / bits() - (N % bits() == 0 ? 1 : 0);
367  const std::size_t m = n / k;
368  const std::size_t l = n % k;
369  for (std::size_t i = 0; i != m; ++i) {
370  std::memcpy(message.data(), C, bytes() * k);
371  for (std::size_t j = 0; j != k; ++j) {
372  t0 += bytes();
373  enc_block(H, message[j], t0, t1);
374  }
375  N -= bits() * k;
376  C += bytes() * k;
377  }
378  std::memcpy(message.data(), C, bytes() * l);
379  for (std::size_t j = 0; j != l; ++j) {
380  t0 += bytes();
381  enc_block(H, message[j], t0, t1);
382  }
383  N -= bits() * l;
384  C += bytes() * l;
385 
386  // Process the last block
387  set_flags(t1, false, true, B);
388  get_block(t0, C, message[0], N);
389  enc_block(H, message[0], t0, t1);
390 
391  return H;
392  }
393 
394  static void ubi_tree_m1(const key_type &G, const param_type &M, int Yl,
395  Vector<key_type> &M1, value_type &t0)
396  {
397  value_type t1 = 0;
398 
399  if (M.bits() == 0) {
400  t0 = 0;
401  set_level(t1, 1);
402  set_type(t1, type_field::msg());
403  M1.push_back(ubi(G, M, t0, t1));
404  }
405 
406  std::size_t Nl = bytes() * (const_one<std::size_t>() << Yl);
407  std::size_t k1 = M.bytes() / Nl + (M.bytes() % Nl == 0 ? 0 : 1);
408  M1.reserve(M1.size() + k1);
409 
410  set_level(t1, 1);
411  set_type(t1, type_field::msg());
412  for (std::size_t i = 0; i != k1;
413  ++i, t0 += static_cast<value_type>(Nl)) {
414  std::size_t N =
415  i + 1 == k1 ? M.bits() - i * Nl * CHAR_BIT : Nl * CHAR_BIT;
416  M1.push_back(ubi(G, param_type(N, M.data() + i * Nl), t0, t1));
417  internal::union_le<char>(M1.back());
418  }
419  }
420 
421  static key_type ubi_tree(
422  const key_type &G, int Yl, int Yf, int Ym, int l, Vector<key_type> &M1)
423  {
424  value_type t0 = 0;
425  value_type t1 = 0;
426 
427  // Process the only block
428  if (M1.size() == 1) {
429  return M1.front();
430  }
431 
432  param_type M(M1.size() * bits(), M1.data());
433 
434  // Process the maximum level
435  if (l + 1 == Ym) {
436  t0 = 0;
437  set_level(t1, Ym);
438  set_type(t1, type_field::msg());
439  return ubi(G, M, t0, t1);
440  }
441 
442  std::size_t Nn = bytes() * (const_one<std::size_t>() << Yf);
443  std::size_t kl = M.bytes() / Nn + (M.bytes() % Nn == 0 ? 0 : 1);
444  set_level(t1, l + 1);
445  set_type(t1, type_field::msg());
446  for (std::size_t i = 0; i != kl; ++i) {
447  t0 = static_cast<value_type>(i * Nn);
448  std::size_t N =
449  i + 1 == kl ? M.bits() - i * Nn * CHAR_BIT : Nn * CHAR_BIT;
450  M1[i] = ubi(G, param_type(N, M.data() + i * Nn), t0, t1);
451  internal::union_le<char>(M1[i]);
452  }
453  M1.resize(kl);
454 
455  return ubi_tree(G, Yl, Yf, Ym, l + 1, M1);
456  }
457 
458  static void output(const key_type &G, std::size_t N, void *H)
459  {
460  N = N / CHAR_BIT + (N % CHAR_BIT == 0 ? 0 : 1);
461  char *C = static_cast<char *>(H);
462 
463  value_type t0 = sizeof(std::uint64_t);
464  value_type t1 = 0;
465  set_type(t1, type_field::out());
466  set_flags(t1, true, true, false);
467  Generator generator;
468  generator.reset(G);
469  generator.tweak(t0, t1);
470 
471  key_type ctr = {{0}};
472  key_type buf = {{0}};
473  const std::size_t n = N / bytes();
474  const std::size_t m = N % bytes();
475  if (n < std::numeric_limits<typename key_type::value_type>::max()) {
476  for (std::size_t i = 0; i != n; ++i) {
477  key_type M = ctr;
478  internal::union_le<char>(M);
479  generator(M.data(), buf.data());
480  buf.front() ^= M.front();
481  std::memcpy(C, buf.data(), bytes());
482  ++ctr.front();
483  C += bytes();
484  }
485  if (m != 0) {
486  key_type M = ctr;
487  internal::union_le<char>(M);
488  generator(M.data(), buf.data());
489  buf.front() ^= M.front();
490  std::memcpy(C, buf.data(), m);
491  }
492  } else {
493  for (std::size_t i = 0; i != n; ++i) {
494  key_type M = ctr;
495  generator(M.data(), buf.data());
496  buf.front() ^= M.front();
497  for (std::size_t j = 0; j != M.size(); ++j) {
498  buf[j] ^= M[j];
499  }
500  std::memcpy(C, buf.data(), bytes());
501  increment(ctr);
502  C += bytes();
503  }
504  if (m != 0) {
505  key_type M = ctr;
506  internal::union_le<char>(M);
507  generator(M.data(), buf.data());
508  for (std::size_t j = 0; j != M.size(); ++j) {
509  buf[j] ^= M[j];
510  }
511  std::memcpy(C, buf.data(), m);
512  }
513  }
514  }
515 
516  static void enc_block(
517  key_type &H, const key_type &M, value_type t0, value_type t1)
518  {
519  Generator generator;
520  generator.reset(H);
521  generator.tweak(t0, t1);
522  generator(M.data(), H.data());
523  for (std::size_t i = 0; i != M.size(); ++i) {
524  H[i] ^= M[i];
525  }
526  internal::union_le<char>(H);
527  }
528 
529  static void set_flags(value_type &t1, bool first, bool last, bool bpad)
530  {
531  constexpr int N = std::numeric_limits<value_type>::digits;
532  constexpr value_type mask_first = const_one<value_type>() << (N - 2);
533  constexpr value_type mask_last = const_one<value_type>() << (N - 1);
534  constexpr value_type mask_bpad = const_one<value_type>() << (N - 9);
535 
536  if (first) {
537  t1 |= mask_first;
538  } else {
539  t1 &= ~mask_first;
540  }
541 
542  if (last) {
543  t1 |= mask_last;
544  if (bpad) {
545  t1 |= mask_bpad;
546  } else {
547  t1 &= ~mask_bpad;
548  }
549  } else {
550  t1 &= ~mask_last;
551  t1 &= ~mask_bpad;
552  }
553  }
554 
555  static void set_type(value_type &t1, int type)
556  {
557  constexpr int N = std::numeric_limits<value_type>::digits;
558  constexpr value_type mask = static_cast<value_type>(0x3F) << (N - 8);
559 
560  t1 &= ~mask;
561  t1 ^= (static_cast<value_type>(type) << (N - 8)) & mask;
562  }
563 
564  static void set_level(value_type &t1, int level)
565  {
566  constexpr int N = std::numeric_limits<value_type>::digits;
567  constexpr value_type mask = static_cast<value_type>(0x7F) << (N - 16);
568 
569  t1 &= ~mask;
570  t1 ^= (static_cast<value_type>(level) << (N - 16)) & mask;
571  }
572 
573  static void get_block(value_type &t0, const char *C, key_type &M)
574  {
575  std::memcpy(M.data(), C, bytes());
576  t0 += bytes();
577  }
578 
579  static void get_block(
580  value_type &t0, const char *C, key_type &M, std::size_t N)
581  {
582  if (N == 0) {
583  std::fill(M.begin(), M.end(), 0);
584  return;
585  }
586 
587  if (N >= bits()) {
588  get_block(t0, C, M);
589  return;
590  }
591 
592  std::array<char, bytes()> tmp = {{0}};
593  std::size_t n = N / CHAR_BIT + (N % CHAR_BIT == 0 ? 0 : 1);
594  std::memcpy(tmp.data(), C, n);
595 
596  N %= CHAR_BIT;
597  if (N != 0) {
598  int R = 7 - static_cast<int>(N);
599  tmp[n - 1] >>= R;
600  tmp[n - 1] |= 1;
601  tmp[n - 1] <<= R;
602  }
603  std::memcpy(M.data(), tmp.data(), bytes());
604  t0 += n;
605  }
606 
607  static std::array<std::uint64_t, 4> configure(
608  std::size_t N, int Yl, int Yf, int Ym)
609  {
610  std::array<std::uint64_t, 4> C = {{0}};
611  std::get<0>(C) = 0x133414853;
612  std::get<1>(C) = static_cast<std::uint64_t>(N);
613  std::get<2>(C) += static_cast<std::uint64_t>(Yl);
614  std::get<2>(C) += static_cast<std::uint64_t>(Yf << 8);
615  std::get<2>(C) += static_cast<std::uint64_t>(Ym << 16);
616 
617  return C;
618  }
619 }; // class Skein
620 
624 
628 
632 
633 } // namespace mckl
634 
636 
637 #endif // MCKL_RANDOM_SKEIN_HPP
void update(state_type &state, const param_type &M) const
Definition: skein.hpp:236
typename key_type::value_type value_type
Type of the key and tweak words.
Definition: skein.hpp:52
state_type init() const
Definition: skein.hpp:142
std::size_t bits() const
The length of the string in bits.
Definition: skein.hpp:99
const char * data() const
The address of the string.
Definition: skein.hpp:108
#define MCKL_PUSH_CLANG_WARNING(warning)
Definition: compiler.h:63
static void hash(std::size_t n, const param_type *M, std::size_t N, void *H, const param_type &K=param_type(), int Yl=0, int Yf=0, int Ym=0)
Full Skein interface.
Definition: skein.hpp:291
Skein hash function.
Definition: skein.hpp:45
typename Generator::key_type key_type
Type of the key.
Definition: skein.hpp:49
Skein::value_type value_type
Definition: skein.hpp:193
static constexpr int key()
Key (for MAC or KDF)
Definition: skein.hpp:59
param_type(std::size_t N=0, const void *data=nullptr, int type=type_field::msg())
Construct a parameter given bit strings.
Definition: skein.hpp:92
ulong uint64_t
Definition: opencl.h:42
std::vector< T, Alloc > Vector
std::vector with Allocator as the default allocator
Definition: memory.hpp:435
static constexpr int pub()
Public key (for digital signature hashing)
Definition: skein.hpp:68
static constexpr int cfg()
Configuration block.
Definition: skein.hpp:62
static constexpr std::size_t bits()
The number of bits of internal state.
Definition: skein.hpp:263
Skein::value_type value_type
Definition: skein.hpp:124
static void hash(const param_type &M, std::size_t N, void *H)
Simple hashing.
Definition: skein.hpp:269
Configure type for stream hasher.
Definition: skein.hpp:120
void output(const state_type &state, void *H) const
Definition: skein.hpp:175
void output(state_type &state, void *H) const
Definition: skein.hpp:244
static constexpr std::size_t bytes()
The number of bytes of internal state.
Definition: skein.hpp:260
void update(state_type &state, const param_type &M) const
Definition: skein.hpp:159
mono_hasher(std::size_t N, const param_type &K=param_type())
Definition: skein.hpp:136
static constexpr int prs()
Personalization string.
Definition: skein.hpp:65
Values of the type field.
Definition: skein.hpp:55
std::size_t bytes() const
The length of the string in bytes.
Definition: skein.hpp:102
tree_hasher(std::size_t N, const param_type &K=param_type(), int Yl=20, int Yf=20, int Ym=2)
Definition: skein.hpp:206
state_type init() const
Definition: skein.hpp:218
static constexpr int kdf()
Key identifier (KDF)
Definition: skein.hpp:71
void increment(std::array< T, K > &ctr, std::integral_constant< T, NSkip >)
Increment a counter by given steps.
int type() const
The type of the string.
Definition: skein.hpp:111
static constexpr int out()
Output.
Definition: skein.hpp:80
Definition: mcmc.hpp:40
#define MCKL_POP_CLANG_WARNING
Definition: compiler.h:66
static constexpr int non()
Nonce (for stream cipher or randomized hashing)
Definition: skein.hpp:74
#define MCKL_ALIGNMENT
The default alignment for scalar type.
Definition: config.h:187
Type of input paramters such as keys and messages.
Definition: skein.hpp:84
static constexpr int msg()
Message.
Definition: skein.hpp:77
void runtime_assert(bool cond, const char *msg, bool soft=false)
Definition: assert.hpp:65