vSMC
vSMC: Scalable Monte Carlo
aes_ni.hpp
Go to the documentation of this file.
1 //============================================================================
2 // vSMC/include/vsmc/rng/aes_ni.hpp
3 //----------------------------------------------------------------------------
4 // vSMC: Scalable Monte Carlo
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2015, 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 VSMC_RNG_AES_NI_HPP
33 #define VSMC_RNG_AES_NI_HPP
34 
36 #include <vsmc/rng/counter.hpp>
37 #include <wmmintrin.h>
38 
39 #define VSMC_STATIC_ASSERT_RNG_AES_NI_BLOCKS(Blocks) \
40  VSMC_STATIC_ASSERT( \
41  (Blocks > 0), "**AESNIGenerator** USED WITH ZERO BLOCKS")
42 
43 #define VSMC_STATIC_ASSERT_RNG_AES_NI_RESULT_TYPE(ResultType) \
44  VSMC_STATIC_ASSERT((std::is_unsigned<ResultType>::value), \
45  "**AESNIGenerator USED WITH ResultType NOT AN UNSIGNED INTEGER")
46 
47 #define VSMC_STATIC_ASSERT_RNG_AES_NI \
48  VSMC_STATIC_ASSERT_RNG_AES_NI_BLOCKS(Blocks); \
49  VSMC_STATIC_ASSERT_RNG_AES_NI_RESULT_TYPE(ResultType);
50 
51 namespace vsmc
52 {
53 
56 template <typename ResultType, typename KeySeqType, std::size_t Rounds,
57  std::size_t Blocks>
59 {
60  public:
61  using result_type = ResultType;
62  using ctr_type = std::array<ResultType, M128I<ResultType>::size()>;
63  using key_type = typename KeySeqType::key_type;
64 
66 
67  static constexpr std::size_t size()
68  {
69  return Blocks * M128I<ResultType>::size();
70  }
71 
72  void reset(const key_type &key) { key_seq_.reset(key); }
73 
74  void operator()(ctr_type &ctr, const key_type &key,
75  std::array<result_type, Blocks * M128I<ResultType>::size()> &buffer)
76  {
77  union {
78  std::array<M128I<>, Blocks> state;
79  std::array<ctr_type, Blocks> ctr_block;
80  std::array<result_type, size()> result;
81  } buf;
82 
83  std::array<M128I<>, Rounds + 1> rk;
84  key_seq_(key, rk);
85  increment(ctr, buf.ctr_block);
86  enc_first(buf.state, rk);
87  enc_round<1>(
88  buf.state, rk, std::integral_constant<bool, 1 < Rounds>());
89  enc_last(buf.state, rk);
90  buffer = buf.result;
91  }
92 
93  std::size_t operator()(ctr_type &ctr, const key_type &key, std::size_t n,
94  result_type *r) const
95  {
96  const std::size_t K = 8;
97  const std::size_t M = K * M128I<ResultType>::size();
98  const std::size_t m = n / M;
99  std::array<M128I<>, Rounds + 1> rk;
100  key_seq_(key, rk);
101  increment(ctr, m * K, reinterpret_cast<ctr_type *>(r));
102  std::array<M128I<>, K> *s =
103  reinterpret_cast<std::array<M128I<>, K> *>(r);
104  for (std::size_t i = 0; i != m; ++i) {
105  enc_first(s[i], rk);
106  enc_round<1>(s[i], rk, std::integral_constant<bool, 1 < Rounds>());
107  enc_last(s[i], rk);
108  }
109  n -= m * M;
110  r += m * M;
111 
112  return m * M;
113  }
114 
115  private:
116  KeySeqType key_seq_;
117 
118  template <std::size_t K>
119  void enc_first(std::array<M128I<>, K> &state,
120  const std::array<M128I<>, Rounds + 1> &rk) const
121  {
122  enc_first<0>(state, rk, std::true_type());
123  }
124 
125  template <std::size_t, std::size_t K>
126  void enc_first(std::array<M128I<>, K> &,
127  const std::array<M128I<>, Rounds + 1> &, std::false_type) const
128  {
129  }
130 
131  template <std::size_t B, std::size_t K>
132  void enc_first(std::array<M128I<>, K> &state,
133  const std::array<M128I<>, Rounds + 1> &rk, std::true_type) const
134  {
135  std::get<B>(state) ^= std::get<0>(rk);
136  enc_first<B + 1>(state, rk, std::integral_constant<bool, B + 1 < K>());
137  }
138 
139  template <std::size_t, std::size_t K>
140  void enc_round(std::array<M128I<>, K> &,
141  const std::array<M128I<>, Rounds + 1> &, std::false_type) const
142  {
143  }
144 
145  template <std::size_t N, std::size_t K>
146  void enc_round(std::array<M128I<>, K> &state,
147  const std::array<M128I<>, Rounds + 1> &rk, std::true_type) const
148  {
149  enc_round_block<0, N>(state, rk, std::true_type());
150  enc_round<N + 1>(
151  state, rk, std::integral_constant<bool, N + 1 < Rounds>());
152  }
153 
154  template <std::size_t, std::size_t, std::size_t K>
155  void enc_round_block(std::array<M128I<>, K> &,
156  const std::array<M128I<>, Rounds + 1> &, std::false_type) const
157  {
158  }
159 
160  template <std::size_t B, std::size_t N, std::size_t K>
161  void enc_round_block(std::array<M128I<>, K> &state,
162  const std::array<M128I<>, Rounds + 1> &rk, std::true_type) const
163  {
164  std::get<B>(state) = _mm_aesenc_si128(
165  std::get<B>(state).value(), std::get<N>(rk).value());
166  enc_round_block<B + 1, N>(
167  state, rk, std::integral_constant<bool, B + 1 < K>());
168  }
169 
170  template <std::size_t K>
171  void enc_last(std::array<M128I<>, K> &state,
172  const std::array<M128I<>, Rounds + 1> &rk) const
173  {
174  enc_last<0>(state, rk, std::true_type());
175  }
176 
177  template <std::size_t, std::size_t K>
178  void enc_last(std::array<M128I<>, K> &,
179  const std::array<M128I<>, Rounds + 1> &, std::false_type) const
180  {
181  }
182 
183  template <std::size_t B, std::size_t K>
184  void enc_last(std::array<M128I<>, K> &state,
185  const std::array<M128I<>, Rounds + 1> &rk, std::true_type) const
186  {
187  std::get<B>(state) = _mm_aesenclast_si128(
188  std::get<B>(state).value(), std::get<Rounds>(rk).value());
189  enc_last<B + 1>(state, rk, std::integral_constant<bool, B + 1 < K>());
190  }
191 }; // class AESNIGenerator
192 
195 template <typename ResultType, typename KeySeqType, std::size_t Rounds,
196  std::size_t Blocks>
197 using AESNIEngine =
199 
200 } // namespace vsmc
201 
202 #endif // VSMC_RNG_AES_NI_HPP
Definition: monitor.hpp:49
void increment(std::array< T, K > &ctr)
Increment a counter by one.
Definition: counter.hpp:62
Counter based RNG engine.
Definition: counter.hpp:290
void operator()(ctr_type &ctr, const key_type &key, std::array< result_type, Blocks *M128I< ResultType >::size()> &buffer)
Definition: aes_ni.hpp:74
static constexpr std::size_t size()
Definition: aes_ni.hpp:67
std::array< ResultType, M128I< ResultType >::size()> ctr_type
Definition: aes_ni.hpp:62
void reset(const key_type &key)
Definition: aes_ni.hpp:72
typename KeySeqType::key_type key_type
Definition: aes_ni.hpp:63
std::size_t operator()(ctr_type &ctr, const key_type &key, std::size_t n, result_type *r) const
Definition: aes_ni.hpp:93
#define VSMC_STATIC_ASSERT_RNG_AES_NI
Definition: aes_ni.hpp:47
ResultType result_type
Definition: aes_ni.hpp:61
RNG generator using AES-NI instructions.
Definition: aes_ni.hpp:58