random123

Counter-based Random Number Generators
git clone git://git.meso-star.com/random123.git
Log | Files | Refs | README | LICENSE

aes.h (13809B)


      1 /*
      2 Copyright 2010-2011, D. E. Shaw Research.
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are
      7 met:
      8 
      9 * Redistributions of source code must retain the above copyright
     10   notice, this list of conditions, and the following disclaimer.
     11 
     12 * Redistributions in binary form must reproduce the above copyright
     13   notice, this list of conditions, and the following disclaimer in the
     14   documentation and/or other materials provided with the distribution.
     15 
     16 * Neither the name of D. E. Shaw Research nor the names of its
     17   contributors may be used to endorse or promote products derived from
     18   this software without specific prior written permission.
     19 
     20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 */
     32 #ifndef __Random123_aes_dot_hpp__
     33 #define __Random123_aes_dot_hpp__
     34 
     35 #include "features/compilerfeatures.h"
     36 #include "array.h"
     37 
     38 /* Implement a bona fide AES block cipher.  It's minimally
     39 // checked against the test vector in FIPS-197 in ut_aes.cpp. */
     40 #if R123_USE_AES_NI
     41 
     42 /** @ingroup AESNI */
     43 typedef struct r123array1xm128i aesni1xm128i_ctr_t;
     44 /** @ingroup AESNI */
     45 typedef struct r123array1xm128i aesni1xm128i_ukey_t;
     46 /** @ingroup AESNI */
     47 typedef struct r123array4x32 aesni4x32_ukey_t;
     48 /** @ingroup AESNI */
     49 enum r123_enum_aesni1xm128i { aesni1xm128i_rounds = 10 };
     50 
     51 /** \cond HIDDEN_FROM_DOXYGEN */
     52 R123_STATIC_INLINE __m128i AES_128_ASSIST (__m128i temp1, __m128i temp2) { 
     53     __m128i temp3; 
     54     temp2 = _mm_shuffle_epi32 (temp2 ,0xff); 
     55     temp3 = _mm_slli_si128 (temp1, 0x4);
     56     temp1 = _mm_xor_si128 (temp1, temp3);
     57     temp3 = _mm_slli_si128 (temp3, 0x4);
     58     temp1 = _mm_xor_si128 (temp1, temp3);
     59     temp3 = _mm_slli_si128 (temp3, 0x4);
     60     temp1 = _mm_xor_si128 (temp1, temp3);
     61     temp1 = _mm_xor_si128 (temp1, temp2); 
     62     return temp1; 
     63 }
     64 
     65 R123_STATIC_INLINE void aesni1xm128iexpand(aesni1xm128i_ukey_t uk, __m128i ret[11])
     66 {
     67     __m128i rkey = uk.v[0].m;
     68     __m128i tmp2;
     69 
     70     ret[0] = rkey;
     71     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x1);
     72     rkey = AES_128_ASSIST(rkey, tmp2);
     73     ret[1] = rkey;
     74 
     75     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x2);
     76     rkey = AES_128_ASSIST(rkey, tmp2);
     77     ret[2] = rkey;
     78 
     79     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x4);
     80     rkey = AES_128_ASSIST(rkey, tmp2);
     81     ret[3] = rkey;
     82 
     83     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x8);
     84     rkey = AES_128_ASSIST(rkey, tmp2);
     85     ret[4] = rkey;
     86 
     87     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x10);
     88     rkey = AES_128_ASSIST(rkey, tmp2);
     89     ret[5] = rkey;
     90 
     91     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x20);
     92     rkey = AES_128_ASSIST(rkey, tmp2);
     93     ret[6] = rkey;
     94 
     95     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x40);
     96     rkey = AES_128_ASSIST(rkey, tmp2);
     97     ret[7] = rkey;
     98 
     99     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x80);
    100     rkey = AES_128_ASSIST(rkey, tmp2);
    101     ret[8] = rkey;
    102 
    103     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x1b);
    104     rkey = AES_128_ASSIST(rkey, tmp2);
    105     ret[9] = rkey;
    106 
    107     tmp2 = _mm_aeskeygenassist_si128(rkey, 0x36);
    108     rkey = AES_128_ASSIST(rkey, tmp2);
    109     ret[10] = rkey;
    110 }
    111 /** \endcond */
    112     
    113 #ifdef __cplusplus
    114 /** @ingroup AESNI */
    115 struct aesni1xm128i_key_t{ 
    116     __m128i k[11]; 
    117     aesni1xm128i_key_t(){
    118         aesni1xm128i_ukey_t uk;
    119         uk.v[0].m = _mm_setzero_si128();
    120         aesni1xm128iexpand(uk, k);
    121     }
    122     aesni1xm128i_key_t(const aesni1xm128i_ukey_t& uk){
    123         aesni1xm128iexpand(uk, k);
    124     }
    125     aesni1xm128i_key_t(const aesni4x32_ukey_t& uk){
    126         aesni1xm128i_ukey_t uk128;
    127         uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]);
    128         aesni1xm128iexpand(uk128, k);
    129     }
    130     aesni1xm128i_key_t& operator=(const aesni1xm128i_ukey_t& uk){
    131         aesni1xm128iexpand(uk, k);
    132         return *this;
    133     }
    134     aesni1xm128i_key_t& operator=(const aesni4x32_ukey_t& uk){
    135         aesni1xm128i_ukey_t uk128;
    136         uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]);
    137         aesni1xm128iexpand(uk128, k);
    138         return *this;
    139     }
    140     bool operator==(const aesni1xm128i_key_t& rhs) const{
    141         for(int i=0; i<11; ++i){
    142             // Sigh... No r123m128i(__m128i) constructor!
    143             r123m128i li; li.m = k[i];
    144             r123m128i ri; ri.m = rhs.k[i];
    145             if( li != ri ) return false;
    146         }
    147         return true;
    148     }
    149     bool operator!=(const aesni1xm128i_key_t& rhs) const{
    150         return !(*this == rhs);
    151     }
    152     friend std::ostream& operator<<(std::ostream& os, const aesni1xm128i_key_t& v){
    153         r123m128i ki;
    154         for(int i=0; i<10; ++i){
    155             ki.m = v.k[i];
    156             os << ki << " ";
    157         }
    158         ki.m = v.k[10];
    159         return os << ki;
    160     }
    161     friend std::istream& operator>>(std::istream& is, aesni1xm128i_key_t& v){
    162         r123m128i ki;
    163         for(int i=0; i<11; ++i){
    164             is >> ki;
    165             v.k[i] = ki;
    166         }
    167         return is;
    168     }
    169 };
    170 #else
    171 typedef struct { 
    172     __m128i k[11]; 
    173 }aesni1xm128i_key_t;
    174 
    175 /** @ingroup AESNI */
    176 R123_STATIC_INLINE aesni1xm128i_key_t aesni1xm128ikeyinit(aesni1xm128i_ukey_t uk){
    177     aesni1xm128i_key_t ret;
    178     aesni1xm128iexpand(uk, ret.k);
    179     return ret;
    180 }
    181 #endif
    182 
    183 /** @ingroup AESNI */
    184 R123_STATIC_INLINE aesni1xm128i_ctr_t aesni1xm128i(aesni1xm128i_ctr_t in, aesni1xm128i_key_t k) {
    185     __m128i x = _mm_xor_si128(k.k[0], in.v[0].m);
    186     x = _mm_aesenc_si128(x, k.k[1]);
    187     x = _mm_aesenc_si128(x, k.k[2]);
    188     x = _mm_aesenc_si128(x, k.k[3]);
    189     x = _mm_aesenc_si128(x, k.k[4]);
    190     x = _mm_aesenc_si128(x, k.k[5]);
    191     x = _mm_aesenc_si128(x, k.k[6]);
    192     x = _mm_aesenc_si128(x, k.k[7]);
    193     x = _mm_aesenc_si128(x, k.k[8]);
    194     x = _mm_aesenc_si128(x, k.k[9]);
    195     x = _mm_aesenclast_si128(x, k.k[10]);
    196     {
    197       aesni1xm128i_ctr_t ret;
    198       ret.v[0].m = x;
    199       return ret;
    200     }
    201 }
    202 
    203 /** @ingroup AESNI */
    204 R123_STATIC_INLINE aesni1xm128i_ctr_t aesni1xm128i_R(unsigned R, aesni1xm128i_ctr_t in, aesni1xm128i_key_t k){
    205     R123_ASSERT(R==10);
    206     return aesni1xm128i(in, k);
    207 }
    208 
    209 
    210 /** @ingroup AESNI */
    211 typedef struct r123array4x32 aesni4x32_ctr_t;
    212 /** @ingroup AESNI */
    213 typedef aesni1xm128i_key_t aesni4x32_key_t;
    214 /** @ingroup AESNI */
    215 enum r123_enum_aesni4x32 { aesni4x32_rounds = 10 };
    216 /** @ingroup AESNI */
    217 R123_STATIC_INLINE aesni4x32_key_t aesni4x32keyinit(aesni4x32_ukey_t uk){
    218     aesni1xm128i_ukey_t uk128;
    219     aesni4x32_key_t ret;
    220     uk128.v[0].m = _mm_set_epi32(uk.v[3], uk.v[2], uk.v[1], uk.v[0]);
    221     aesni1xm128iexpand(uk128, ret.k);
    222     return ret;
    223 }
    224 
    225 /** @ingroup AESNI */
    226 /** The aesni4x32_R function provides a C API to the @ref AESNI "AESNI" CBRNG, allowing the number of rounds to be specified explicitly **/
    227 R123_STATIC_INLINE aesni4x32_ctr_t aesni4x32_R(unsigned int Nrounds, aesni4x32_ctr_t c, aesni4x32_key_t k){
    228     aesni1xm128i_ctr_t c128;
    229     c128.v[0].m = _mm_set_epi32(c.v[3], c.v[2], c.v[1], c.v[0]);
    230     c128 = aesni1xm128i_R(Nrounds, c128, k);
    231     _mm_storeu_si128((__m128i*)&c.v[0], c128.v[0].m);
    232     return c;
    233 }
    234 
    235 #define aesni4x32_rounds aesni1xm128i_rounds
    236 
    237 /** The aesni4x32 macro provides a C API to the @ref AESNI "AESNI" CBRNG, uses the default number of rounds i.e. \c aesni4x32_rounds **/
    238 /** @ingroup AESNI */
    239 #define aesni4x32(c,k) aesni4x32_R(aesni4x32_rounds, c, k)
    240 
    241 #ifdef __cplusplus
    242 namespace r123{
    243 /** 
    244 @defgroup AESNI ARS and AESNI Classes and Typedefs
    245 
    246 The ARS4x32, ARS1xm128i, AESNI4x32 and AESNI1xm128i classes export the member functions, typedefs and
    247 operator overloads required by a @ref CBRNG "CBRNG" class.
    248 
    249 ARS1xm128i and AESNI1xm128i are based on the AES block cipher and rely on the AES-NI hardware instructions
    250 available on some some new (2011) CPUs.
    251 
    252 The ARS1xm128i CBRNG and the use of AES for random number generation are described in 
    253 <a href="http://dl.acm.org/citation.cfm?doid=2063405"><i>Parallel Random Numbers:  As Easy as 1, 2, 3</i> </a>.
    254 Although it uses some cryptographic primitives, ARS1xm128i uses a cryptographically weak key schedule and is \b not suitable for cryptographic use.
    255 
    256 @class AESNI1xm128i
    257 @ingroup AESNI
    258 AESNI exports the member functions, typedefs and operator overloads required by a @ref CBRNG class.
    259 
    260 AESNI1xm128i uses the crypotgraphic AES round function, including the cryptographic key schedule.
    261 
    262 In contrast to the other CBRNGs in the Random123 library, the AESNI1xm128i_R::key_type is opaque
    263 and is \b not identical to the AESNI1xm128i_R::ukey_type.  Creating a key_type, using either the constructor
    264 or assignment operator, is significantly more time-consuming than running the bijection (hundreds
    265 of clock cycles vs. tens of clock cycles).
    266 
    267 AESNI1xm128i is only available when the feature-test macro R123_USE_AES_NI is true, which
    268 should occur only when the compiler is configured to generate AES-NI instructions (or
    269 when defaults are overridden by compile-time, compiler-command-line options).
    270 
    271 As of September 2011, the authors know of no statistical flaws with AESNI1xm128i.  It
    272 would be an event of major cryptographic note if any such flaws were ever found.
    273 */
    274 struct AESNI1xm128i{
    275     typedef aesni1xm128i_ctr_t ctr_type;
    276     typedef aesni1xm128i_ukey_t ukey_type;
    277     typedef aesni1xm128i_key_t key_type;
    278     static const unsigned int rounds=10;
    279     ctr_type operator()(ctr_type ctr, key_type key) const{
    280         return aesni1xm128i(ctr, key);
    281     }
    282 };
    283 
    284 /* @class AESNI4x32 */
    285 struct AESNI4x32{
    286     typedef aesni4x32_ctr_t ctr_type;
    287     typedef aesni4x32_ukey_t ukey_type;
    288     typedef aesni4x32_key_t key_type;
    289     static const unsigned int rounds=10;
    290     ctr_type operator()(ctr_type ctr, key_type key) const{
    291         return aesni4x32(ctr, key);
    292     }
    293 };
    294 
    295 /** @ingroup AESNI
    296     @class AESNI1xm128i_R
    297 
    298 AESNI1xm128i_R is provided for completeness, but is only instantiable with ROUNDS=10, in
    299 which case it is identical to AESNI1xm128i */
    300 template <unsigned ROUNDS=10> 
    301 struct AESNI1xm128i_R : public AESNI1xm128i{
    302     R123_STATIC_ASSERT(ROUNDS==10, "AESNI1xm128i_R<R> is only valid with R=10");
    303 };
    304 
    305 /** @class AESNI4x32_R **/
    306 template <unsigned ROUNDS=10> 
    307 struct AESNI4x32_R : public AESNI4x32{
    308     R123_STATIC_ASSERT(ROUNDS==10, "AESNI4x32_R<R> is only valid with R=10");
    309 };
    310 } // namespace r123
    311 #endif /* __cplusplus */
    312 
    313 #endif /* R123_USE_AES_NI */
    314 
    315 #if R123_USE_AES_OPENSSL
    316 #include "string.h"
    317 #include <openssl/aes.h>
    318 typedef struct r123array16x8 aesopenssl16x8_ctr_t;
    319 typedef struct r123array16x8 aesopenssl16x8_ukey_t;
    320 #ifdef __cplusplus
    321 struct aesopenssl16x8_key_t{
    322     AES_KEY k;
    323     aesopenssl16x8_key_t(){
    324         aesopenssl16x8_ukey_t ukey={{}};
    325         AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k);
    326     }
    327     aesopenssl16x8_key_t(const aesopenssl16x8_ukey_t& ukey){
    328         AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k);
    329     }
    330     aesopenssl16x8_key_t& operator=(const aesopenssl16x8_ukey_t& ukey){
    331         AES_set_encrypt_key((const unsigned char *)&ukey.v[0], 128, &k);
    332         return *this;
    333     }
    334     bool operator==(const aesopenssl16x8_key_t& rhs) const{
    335         return (k.rounds == rhs.k.rounds) && 0==::memcmp(&k.rd_key[0], &rhs.k.rd_key[0], (k.rounds+1) * 4 * sizeof(uint32_t));
    336     }
    337     bool operator!=(const aesopenssl16x8_key_t& rhs) const{
    338         return !(*this == rhs);
    339     }
    340     friend std::ostream& operator<<(std::ostream& os, const aesopenssl16x8_key_t& v){
    341         os << v.k.rounds;
    342         const unsigned int *p = &v.k.rd_key[0];
    343         for(int i=0; i<(v.k.rounds+1); ++i){
    344             os << " " << p[0] << " " << p[1] << " " << p[2] << " " << p[3];
    345             p += 4;
    346         }
    347         return os;
    348     }
    349     friend std::istream& operator>>(std::istream& is, aesopenssl16x8_key_t& v){
    350         is >> v.k.rounds;
    351         unsigned int *p = &v.k.rd_key[0];
    352         for(int i=0; i<(v.k.rounds+1); ++i){
    353             is >> p[0] >> p[1] >> p[2] >> p[3];
    354             p += 4;
    355         }
    356         return is;
    357     }
    358 };
    359 #else
    360 typedef struct aesopenssl16x8_key_t{
    361     AES_KEY k;
    362 }aesopenssl16x8_key_t;
    363 R123_STATIC_INLINE struct aesopenssl16x8_key_t aesopenssl16x8keyinit(aesopenssl16x8_ukey_t uk){
    364     aesopenssl16x8_key_t ret;
    365     AES_set_encrypt_key((const unsigned char *)&uk.v[0], 128, &ret.k);
    366     return ret;
    367 }
    368 #endif
    369 
    370 R123_STATIC_INLINE R123_FORCE_INLINE(aesopenssl16x8_ctr_t aesopenssl16x8_R(aesopenssl16x8_ctr_t ctr, aesopenssl16x8_key_t key));
    371 R123_STATIC_INLINE
    372 aesopenssl16x8_ctr_t aesopenssl16x8_R(aesopenssl16x8_ctr_t ctr, aesopenssl16x8_key_t key){
    373     aesopenssl16x8_ctr_t ret;
    374     AES_encrypt((const unsigned char*)&ctr.v[0], (unsigned char *)&ret.v[0], &key.k);
    375     return ret;
    376 }
    377 
    378 #define aesopenssl16x8_rounds aesni4x32_rounds
    379 #define aesopenssl16x8(c,k) aesopenssl16x8_R(aesopenssl16x8_rounds)
    380 
    381 #ifdef __cplusplus
    382 namespace r123{
    383 struct AESOpenSSL16x8{
    384     typedef aesopenssl16x8_ctr_t ctr_type;
    385     typedef aesopenssl16x8_key_t key_type;
    386     typedef aesopenssl16x8_ukey_t ukey_type;
    387     static const unsigned int rounds=10;
    388     ctr_type operator()(const ctr_type& in, const key_type& k){
    389         ctr_type out;
    390         AES_encrypt((const unsigned char *)&in[0], (unsigned char *)&out[0], &k.k);
    391         return out;
    392     }
    393 };
    394 } // namespace r123
    395 #endif /* __cplusplus */
    396 #endif /* R123_USE_AES_OPENSSL */
    397 
    398 #endif