random123

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

threefry.h (49191B)


      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 _threefry_dot_h_
     33 #define _threefry_dot_h_
     34 #include "features/compilerfeatures.h"
     35 #include "array.h"
     36 
     37 /** \cond HIDDEN_FROM_DOXYGEN */
     38 /* Significant parts of this file were copied from
     39    from:
     40       Skein_FinalRnd/ReferenceImplementation/skein.h
     41       Skein_FinalRnd/ReferenceImplementation/skein_block.c
     42 
     43    in http://csrc.nist.gov/groups/ST/hash/sha-3/Round3/documents/Skein_FinalRnd.zip
     44 
     45    This file has been modified so that it may no longer perform its originally
     46    intended function.  If you're looking for a Skein or Threefish source code,
     47    please consult the original file.
     48 
     49    The original file had the following header:
     50 **************************************************************************
     51 **
     52 ** Interface declarations and internal definitions for Skein hashing.
     53 **
     54 ** Source code author: Doug Whiting, 2008.
     55 **
     56 ** This algorithm and source code is released to the public domain.
     57 **
     58 ***************************************************************************
     59 
     60 */
     61 
     62 /* See comment at the top of philox.h for the macro pre-process
     63    strategy. */
     64 
     65 /* Rotation constants: */
     66 enum r123_enum_threefry64x4 {
     67     /* These are the R_256 constants from the Threefish reference sources
     68        with names changed to R_64x4... */
     69     R_64x4_0_0=14, R_64x4_0_1=16,
     70     R_64x4_1_0=52, R_64x4_1_1=57,
     71     R_64x4_2_0=23, R_64x4_2_1=40,
     72     R_64x4_3_0= 5, R_64x4_3_1=37,
     73     R_64x4_4_0=25, R_64x4_4_1=33,
     74     R_64x4_5_0=46, R_64x4_5_1=12,
     75     R_64x4_6_0=58, R_64x4_6_1=22,
     76     R_64x4_7_0=32, R_64x4_7_1=32
     77 };
     78 
     79 enum r123_enum_threefry64x2 {
     80     /*
     81     // Output from skein_rot_search: (srs64_B64-X1000)
     82     // Random seed = 1. BlockSize = 128 bits. sampleCnt =  1024. rounds =  8, minHW_or=57
     83     // Start: Tue Mar  1 10:07:48 2011
     84     // rMin = 0.136. #0325[*15] [CRC=455A682F. hw_OR=64. cnt=16384. blkSize= 128].format   
     85     */
     86     R_64x2_0_0=16,
     87     R_64x2_1_0=42,
     88     R_64x2_2_0=12,
     89     R_64x2_3_0=31,
     90     R_64x2_4_0=16,
     91     R_64x2_5_0=32,
     92     R_64x2_6_0=24,
     93     R_64x2_7_0=21
     94     /* 4 rounds: minHW =  4  [  4  4  4  4 ]
     95     // 5 rounds: minHW =  8  [  8  8  8  8 ]
     96     // 6 rounds: minHW = 16  [ 16 16 16 16 ]
     97     // 7 rounds: minHW = 32  [ 32 32 32 32 ]
     98     // 8 rounds: minHW = 64  [ 64 64 64 64 ]
     99     // 9 rounds: minHW = 64  [ 64 64 64 64 ]
    100     //10 rounds: minHW = 64  [ 64 64 64 64 ]
    101     //11 rounds: minHW = 64  [ 64 64 64 64 ] */
    102 };
    103 
    104 enum r123_enum_threefry32x4 {
    105     /* Output from skein_rot_search: (srs-B128-X5000.out)
    106     // Random seed = 1. BlockSize = 64 bits. sampleCnt =  1024. rounds =  8, minHW_or=28
    107     // Start: Mon Aug 24 22:41:36 2009
    108     // ...
    109     // rMin = 0.472. #0A4B[*33] [CRC=DD1ECE0F. hw_OR=31. cnt=16384. blkSize= 128].format    */
    110     R_32x4_0_0=10, R_32x4_0_1=26,
    111     R_32x4_1_0=11, R_32x4_1_1=21,
    112     R_32x4_2_0=13, R_32x4_2_1=27,
    113     R_32x4_3_0=23, R_32x4_3_1= 5,
    114     R_32x4_4_0= 6, R_32x4_4_1=20,
    115     R_32x4_5_0=17, R_32x4_5_1=11,
    116     R_32x4_6_0=25, R_32x4_6_1=10,
    117     R_32x4_7_0=18, R_32x4_7_1=20
    118 
    119     /* 4 rounds: minHW =  3  [  3  3  3  3 ]
    120     // 5 rounds: minHW =  7  [  7  7  7  7 ]
    121     // 6 rounds: minHW = 12  [ 13 12 13 12 ]
    122     // 7 rounds: minHW = 22  [ 22 23 22 23 ]
    123     // 8 rounds: minHW = 31  [ 31 31 31 31 ]
    124     // 9 rounds: minHW = 32  [ 32 32 32 32 ]
    125     //10 rounds: minHW = 32  [ 32 32 32 32 ]
    126     //11 rounds: minHW = 32  [ 32 32 32 32 ] */
    127 
    128 };
    129 
    130 enum r123_enum_threefry32x2 {
    131     /* Output from skein_rot_search (srs32x2-X5000.out)
    132     // Random seed = 1. BlockSize = 64 bits. sampleCnt =  1024. rounds =  8, minHW_or=28
    133     // Start: Tue Jul 12 11:11:33 2011
    134     // rMin = 0.334. #0206[*07] [CRC=1D9765C0. hw_OR=32. cnt=16384. blkSize=  64].format   */
    135     R_32x2_0_0=13,
    136     R_32x2_1_0=15,
    137     R_32x2_2_0=26,
    138     R_32x2_3_0= 6,
    139     R_32x2_4_0=17,
    140     R_32x2_5_0=29,
    141     R_32x2_6_0=16,
    142     R_32x2_7_0=24
    143 
    144     /* 4 rounds: minHW =  4  [  4  4  4  4 ]
    145     // 5 rounds: minHW =  6  [  6  8  6  8 ]
    146     // 6 rounds: minHW =  9  [  9 12  9 12 ]
    147     // 7 rounds: minHW = 16  [ 16 24 16 24 ]
    148     // 8 rounds: minHW = 32  [ 32 32 32 32 ]
    149     // 9 rounds: minHW = 32  [ 32 32 32 32 ]
    150     //10 rounds: minHW = 32  [ 32 32 32 32 ]
    151     //11 rounds: minHW = 32  [ 32 32 32 32 ] */
    152     };
    153 
    154 enum r123_enum_threefry_wcnt {
    155     WCNT2=2,
    156     WCNT4=4
    157 };
    158 
    159 #if R123_USE_64BIT
    160 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(uint64_t RotL_64(uint64_t x, unsigned int N));
    161 R123_CUDA_DEVICE R123_STATIC_INLINE uint64_t RotL_64(uint64_t x, unsigned int N)
    162 {
    163     return (x << (N & 63)) | (x >> ((64-N) & 63));
    164 }
    165 #endif
    166 
    167 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(uint32_t RotL_32(uint32_t x, unsigned int N));
    168 R123_CUDA_DEVICE R123_STATIC_INLINE uint32_t RotL_32(uint32_t x, unsigned int N)
    169 {
    170     return (x << (N & 31)) | (x >> ((32-N) & 31));
    171 }
    172 
    173 #define SKEIN_MK_64(hi32,lo32)  ((lo32) + (((uint64_t) (hi32)) << 32))
    174 #define SKEIN_KS_PARITY64         SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22)
    175 #define SKEIN_KS_PARITY32         0x1BD11BDA
    176 
    177 /** \endcond */
    178 
    179 #ifndef THREEFRY2x32_DEFAULT_ROUNDS
    180 #define THREEFRY2x32_DEFAULT_ROUNDS 20
    181 #endif
    182 
    183 #ifndef THREEFRY2x64_DEFAULT_ROUNDS
    184 #define THREEFRY2x64_DEFAULT_ROUNDS 20
    185 #endif
    186 
    187 #ifndef THREEFRY4x32_DEFAULT_ROUNDS
    188 #define THREEFRY4x32_DEFAULT_ROUNDS 20
    189 #endif
    190 
    191 #ifndef THREEFRY4x64_DEFAULT_ROUNDS
    192 #define THREEFRY4x64_DEFAULT_ROUNDS 20
    193 #endif
    194 
    195 #define _threefry2x_tpl(W)                                              \
    196 typedef struct r123array2x##W threefry2x##W##_ctr_t;                          \
    197 typedef struct r123array2x##W threefry2x##W##_key_t;                          \
    198 typedef struct r123array2x##W threefry2x##W##_ukey_t;                          \
    199 R123_CUDA_DEVICE R123_STATIC_INLINE threefry2x##W##_key_t threefry2x##W##keyinit(threefry2x##W##_ukey_t uk) { return uk; } \
    200 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(threefry2x##W##_ctr_t threefry2x##W##_R(unsigned int Nrounds, threefry2x##W##_ctr_t in, threefry2x##W##_key_t k)); \
    201 R123_CUDA_DEVICE R123_STATIC_INLINE                                          \
    202 threefry2x##W##_ctr_t threefry2x##W##_R(unsigned int Nrounds, threefry2x##W##_ctr_t in, threefry2x##W##_key_t k){ \
    203     uint##W##_t X0,X1; \
    204     uint##W##_t ks0, ks1, ks2; \
    205     R123_ASSERT(Nrounds<=32);                                           \
    206     ks2 =  SKEIN_KS_PARITY##W;                                   \
    207     ks0 = k.v[0];                                                       \
    208     X0  = in.v[0] + ks0;                                                  \
    209     ks2 ^= ks0; \
    210 \
    211     ks1 = k.v[1];                                                       \
    212     X1  = in.v[1] + ks1;                                                  \
    213     ks2 ^= ks1; \
    214                                                                         \
    215     if(Nrounds>0){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_0_0); X1 ^= X0; } \
    216     if(Nrounds>1){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_1_0); X1 ^= X0; } \
    217     if(Nrounds>2){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_2_0); X1 ^= X0; } \
    218     if(Nrounds>3){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_3_0); X1 ^= X0; } \
    219     if(Nrounds>3){                                                      \
    220         /* InjectKey(r=1) */                                            \
    221         X0 += ks1; X1 += ks2;                               \
    222         X1 += 1;     /* X.v[2-1] += r  */                   \
    223     }                                                                   \
    224     if(Nrounds>4){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_4_0); X1 ^= X0; } \
    225     if(Nrounds>5){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_5_0); X1 ^= X0; } \
    226     if(Nrounds>6){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_6_0); X1 ^= X0; } \
    227     if(Nrounds>7){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_7_0); X1 ^= X0; } \
    228     if(Nrounds>7){                                                      \
    229         /* InjectKey(r=2) */                                            \
    230         X0 += ks2; X1 += ks0;                               \
    231         X1 += 2;                                                    \
    232     }                                                                   \
    233     if(Nrounds>8){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_0_0); X1 ^= X0; } \
    234     if(Nrounds>9){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_1_0); X1 ^= X0; } \
    235     if(Nrounds>10){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_2_0); X1 ^= X0; } \
    236     if(Nrounds>11){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_3_0); X1 ^= X0; } \
    237     if(Nrounds>11){                                                     \
    238         /* InjectKey(r=3) */                                            \
    239         X0 += ks0; X1 += ks1;                               \
    240         X1 += 3;                                                    \
    241     }                                                                   \
    242     if(Nrounds>12){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_4_0); X1 ^= X0; } \
    243     if(Nrounds>13){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_5_0); X1 ^= X0; } \
    244     if(Nrounds>14){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_6_0); X1 ^= X0; } \
    245     if(Nrounds>15){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_7_0); X1 ^= X0; } \
    246     if(Nrounds>15){                                                     \
    247         /* InjectKey(r=4) */                                            \
    248         X0 += ks1; X1 += ks2;                               \
    249         X1 += 4;                                                    \
    250     }                                                                   \
    251     if(Nrounds>16){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_0_0); X1 ^= X0; } \
    252     if(Nrounds>17){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_1_0); X1 ^= X0; } \
    253     if(Nrounds>18){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_2_0); X1 ^= X0; } \
    254     if(Nrounds>19){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_3_0); X1 ^= X0; } \
    255     if(Nrounds>19){                                                     \
    256         /* InjectKey(r=5) */                                            \
    257         X0 += ks2; X1 += ks0;                               \
    258         X1 += 5;                                                    \
    259     }                                                                   \
    260     if(Nrounds>20){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_4_0); X1 ^= X0; } \
    261     if(Nrounds>21){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_5_0); X1 ^= X0; } \
    262     if(Nrounds>22){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_6_0); X1 ^= X0; } \
    263     if(Nrounds>23){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_7_0); X1 ^= X0; } \
    264     if(Nrounds>23){                                                     \
    265         /* InjectKey(r=6) */                                            \
    266         X0 += ks0; X1 += ks1;                               \
    267         X1 += 6;                                                    \
    268     }                                                                   \
    269     if(Nrounds>24){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_0_0); X1 ^= X0; } \
    270     if(Nrounds>25){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_1_0); X1 ^= X0; } \
    271     if(Nrounds>26){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_2_0); X1 ^= X0; } \
    272     if(Nrounds>27){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_3_0); X1 ^= X0; } \
    273     if(Nrounds>27){                                                     \
    274         /* InjectKey(r=7) */                                            \
    275         X0 += ks1; X1 += ks2;                               \
    276         X1 += 7;                                                    \
    277     }                                                                   \
    278     if(Nrounds>28){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_4_0); X1 ^= X0; } \
    279     if(Nrounds>29){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_5_0); X1 ^= X0; } \
    280     if(Nrounds>30){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_6_0); X1 ^= X0; } \
    281     if(Nrounds>31){  X0 += X1; X1 = RotL_##W(X1,R_##W##x2_7_0); X1 ^= X0; } \
    282     if(Nrounds>31){                                                     \
    283         /* InjectKey(r=8) */                                            \
    284         X0 += ks2; X1 += ks0;                               \
    285         X1 += 8;                                                    \
    286     }                                                                   \
    287     threefry2x##W##_ctr_t ret={{X0, X1}};                                   \
    288     return ret;                                                             \
    289 }                                                                       \
    290  /** @ingroup ThreefryNxW */                                            \
    291 enum r123_enum_threefry2x##W { threefry2x##W##_rounds = THREEFRY2x##W##_DEFAULT_ROUNDS };       \
    292 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(threefry2x##W##_ctr_t threefry2x##W(threefry2x##W##_ctr_t in, threefry2x##W##_key_t k)); \
    293 R123_CUDA_DEVICE R123_STATIC_INLINE                                     \
    294 threefry2x##W##_ctr_t threefry2x##W(threefry2x##W##_ctr_t in, threefry2x##W##_key_t k){ \
    295     return threefry2x##W##_R(threefry2x##W##_rounds, in, k);            \
    296 }
    297 
    298 
    299 #define _threefry4x_tpl(W)                                              \
    300 typedef struct r123array4x##W threefry4x##W##_ctr_t;                        \
    301 typedef struct r123array4x##W threefry4x##W##_key_t;                        \
    302 typedef struct r123array4x##W threefry4x##W##_ukey_t;                        \
    303 R123_CUDA_DEVICE R123_STATIC_INLINE threefry4x##W##_key_t threefry4x##W##keyinit(threefry4x##W##_ukey_t uk) { return uk; } \
    304 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(threefry4x##W##_ctr_t threefry4x##W##_R(unsigned int Nrounds, threefry4x##W##_ctr_t in, threefry4x##W##_key_t k)); \
    305 R123_CUDA_DEVICE R123_STATIC_INLINE                                          \
    306 threefry4x##W##_ctr_t threefry4x##W##_R(unsigned int Nrounds, threefry4x##W##_ctr_t in, threefry4x##W##_key_t k){ \
    307     uint##W##_t X0, X1, X2, X3; \
    308     uint##W##_t ks0, ks1, ks2, ks3, ks4;                          \
    309     R123_ASSERT(Nrounds<=72);                                           \
    310     ks4 =  SKEIN_KS_PARITY##W;                                    \
    311     ks0 = k.v[0]; \
    312     X0 = in.v[0] + ks0;  \
    313     ks4 ^= ks0;                            \
    314     \
    315     ks1 = k.v[1]; \
    316     X1 = in.v[1] + ks1;  \
    317     ks4 ^= ks1;                            \
    318     \
    319     ks2 = k.v[2]; \
    320     X2 = in.v[2] + ks2;  \
    321     ks4 ^= ks2;                            \
    322     \
    323     ks3 = k.v[3]; \
    324     X3 = in.v[3] + ks3;  \
    325     ks4 ^= ks3;                                                    \
    326                                                                         \
    327     if(Nrounds>0){                                                      \
    328         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    329         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    330     }                                                                   \
    331     if(Nrounds>1){                                                      \
    332         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    333         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    334     }                                                                   \
    335     if(Nrounds>2){                                                      \
    336         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    337         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    338     }                                                                   \
    339     if(Nrounds>3){                                                      \
    340         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    341         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    342     }                                                                   \
    343     if(Nrounds>3){                                                      \
    344         /* InjectKey(r=1) */                                            \
    345         X0 += ks1; X1 += ks2; X2 += ks3; X3 += ks4; \
    346         X3 += 1;     /* XWCNT4-1 += r  */                 \
    347     }                                                                   \
    348                                                                         \
    349     if(Nrounds>4){                                                      \
    350         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    351         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    352     }                                                                   \
    353     if(Nrounds>5){                                                      \
    354         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    355         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    356     }                                                                   \
    357     if(Nrounds>6){                                                      \
    358         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    359         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    360     }                                                                   \
    361     if(Nrounds>7){                                                      \
    362         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    363         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    364     }                                                                   \
    365     if(Nrounds>7){                                                      \
    366         /* InjectKey(r=2) */                                            \
    367         X0 += ks2; X1 += ks3; X2 += ks4; X3 += ks0; \
    368         X3 += 2;     /* XWCNT4-1 += r  */                 \
    369     }                                                                   \
    370                                                                         \
    371     if(Nrounds>8){                                                      \
    372         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    373         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    374     }                                                                   \
    375     if(Nrounds>9){                                                      \
    376         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    377         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    378     }                                                                   \
    379     if(Nrounds>10){                                                     \
    380         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    381         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    382     }                                                                   \
    383     if(Nrounds>11){                                                     \
    384         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    385         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    386     }                                                                   \
    387     if(Nrounds>11){                                                     \
    388         /* InjectKey(r=3) */                                            \
    389         X0 += ks3; X1 += ks4; X2 += ks0; X3 += ks1; \
    390         X3 += 3;     /* XWCNT4-1 += r  */                 \
    391     }                                                                   \
    392                                                                         \
    393     if(Nrounds>12){                                                     \
    394         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    395         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    396     }                                                                   \
    397     if(Nrounds>13){                                                     \
    398         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    399         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    400     }                                                                   \
    401     if(Nrounds>14){                                                     \
    402         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    403         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    404     }                                                                   \
    405     if(Nrounds>15){                                                     \
    406         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    407         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    408     }                                                                   \
    409     if(Nrounds>15){                                                     \
    410         /* InjectKey(r=1) */                                            \
    411         X0 += ks4; X1 += ks0; X2 += ks1; X3 += ks2; \
    412         X3 += 4;     /* XWCNT4-1 += r  */                 \
    413     }                                                                   \
    414                                                                         \
    415     if(Nrounds>16){                                                     \
    416         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    417         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    418     }                                                                   \
    419     if(Nrounds>17){                                                     \
    420         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    421         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    422     }                                                                   \
    423     if(Nrounds>18){                                                     \
    424         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    425         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    426     }                                                                   \
    427     if(Nrounds>19){                                                     \
    428         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    429         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    430     }                                                                   \
    431     if(Nrounds>19){                                                     \
    432         /* InjectKey(r=1) */                                            \
    433         X0 += ks0; X1 += ks1; X2 += ks2; X3 += ks3; \
    434         X3 += 5;     /* XWCNT4-1 += r  */                 \
    435     }                                                                   \
    436                                                                         \
    437     if(Nrounds>20){                                                     \
    438         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    439         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    440     }                                                                   \
    441     if(Nrounds>21){                                                     \
    442         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    443         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    444     }                                                                   \
    445     if(Nrounds>22){                                                     \
    446         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    447         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    448     }                                                                   \
    449     if(Nrounds>23){                                                     \
    450         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    451         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    452     }                                                                   \
    453     if(Nrounds>23){                                                     \
    454         /* InjectKey(r=1) */                                            \
    455         X0 += ks1; X1 += ks2; X2 += ks3; X3 += ks4; \
    456         X3 += 6;     /* XWCNT4-1 += r  */                 \
    457     }                                                                   \
    458                                                                         \
    459     if(Nrounds>24){                                                     \
    460         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    461         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    462     }                                                                   \
    463     if(Nrounds>25){                                                     \
    464         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    465         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    466     }                                                                   \
    467     if(Nrounds>26){                                                     \
    468         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    469         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    470     }                                                                   \
    471     if(Nrounds>27){                                                     \
    472         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    473         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    474     }                                                                   \
    475     if(Nrounds>27){                                                     \
    476         /* InjectKey(r=1) */                                            \
    477         X0 += ks2; X1 += ks3; X2 += ks4; X3 += ks0; \
    478         X3 += 7;     /* XWCNT4-1 += r  */                 \
    479     }                                                                   \
    480                                                                         \
    481     if(Nrounds>28){                                                     \
    482         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    483         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    484     }                                                                   \
    485     if(Nrounds>29){                                                     \
    486         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    487         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    488     }                                                                   \
    489     if(Nrounds>30){                                                     \
    490         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    491         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    492     }                                                                   \
    493     if(Nrounds>31){                                                     \
    494         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    495         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    496     }                                                                   \
    497     if(Nrounds>31){                                                     \
    498         /* InjectKey(r=1) */                                            \
    499         X0 += ks3; X1 += ks4; X2 += ks0; X3 += ks1; \
    500         X3 += 8;     /* XWCNT4-1 += r  */                 \
    501     }                                                                   \
    502                                                                         \
    503     if(Nrounds>32){                                                     \
    504         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    505         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    506     }                                                                   \
    507     if(Nrounds>33){                                                     \
    508         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    509         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    510     }                                                                   \
    511     if(Nrounds>34){                                                     \
    512         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    513         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    514     }                                                                   \
    515     if(Nrounds>35){                                                     \
    516         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    517         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    518     }                                                                   \
    519     if(Nrounds>35){                                                     \
    520         /* InjectKey(r=1) */                                            \
    521         X0 += ks4; X1 += ks0; X2 += ks1; X3 += ks2; \
    522         X3 += 9;     /* XWCNT4-1 += r  */                 \
    523     }                                                                   \
    524                                                                         \
    525     if(Nrounds>36){                                                     \
    526         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    527         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    528     }                                                                   \
    529     if(Nrounds>37){                                                     \
    530         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    531         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    532     }                                                                   \
    533     if(Nrounds>38){                                                     \
    534         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    535         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    536     }                                                                   \
    537     if(Nrounds>39){                                                     \
    538         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    539         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    540     }                                                                   \
    541     if(Nrounds>39){                                                     \
    542         /* InjectKey(r=1) */                                            \
    543         X0 += ks0; X1 += ks1; X2 += ks2; X3 += ks3; \
    544         X3 += 10;     /* XWCNT4-1 += r  */                 \
    545     }                                                                   \
    546                                                                         \
    547     if(Nrounds>40){                                                     \
    548         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    549         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    550     }                                                                   \
    551     if(Nrounds>41){                                                     \
    552         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    553         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    554     }                                                                   \
    555     if(Nrounds>42){                                                     \
    556         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    557         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    558     }                                                                   \
    559     if(Nrounds>43){                                                     \
    560         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    561         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    562     }                                                                   \
    563     if(Nrounds>43){                                                     \
    564         /* InjectKey(r=1) */                                            \
    565         X0 += ks1; X1 += ks2; X2 += ks3; X3 += ks4; \
    566         X3 += 11;     /* XWCNT4-1 += r  */                \
    567     }                                                                   \
    568                                                                         \
    569     if(Nrounds>44){                                                     \
    570         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    571         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    572     }                                                                   \
    573     if(Nrounds>45){                                                     \
    574         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    575         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    576     }                                                                   \
    577     if(Nrounds>46){                                                     \
    578         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    579         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    580     }                                                                   \
    581     if(Nrounds>47){                                                     \
    582         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    583         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    584     }                                                                   \
    585     if(Nrounds>47){                                                     \
    586         /* InjectKey(r=1) */                                            \
    587         X0 += ks2; X1 += ks3; X2 += ks4; X3 += ks0; \
    588         X3 += 12;     /* XWCNT4-1 += r  */                 \
    589     }                                                                   \
    590                                                                         \
    591     if(Nrounds>48){                                                     \
    592         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    593         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    594     }                                                                   \
    595     if(Nrounds>49){                                                     \
    596         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    597         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    598     }                                                                   \
    599     if(Nrounds>50){                                                     \
    600         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    601         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    602     }                                                                   \
    603     if(Nrounds>51){                                                     \
    604         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    605         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    606     }                                                                   \
    607     if(Nrounds>51){                                                     \
    608         /* InjectKey(r=1) */                                            \
    609         X0 += ks3; X1 += ks4; X2 += ks0; X3 += ks1; \
    610         X3 += 13;     /* XWCNT4-1 += r  */                 \
    611     }                                                                   \
    612                                                                         \
    613     if(Nrounds>52){                                                     \
    614         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    615         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    616     }                                                                   \
    617     if(Nrounds>53){                                                     \
    618         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    619         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    620     }                                                                   \
    621     if(Nrounds>54){                                                     \
    622         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    623         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    624     }                                                                   \
    625     if(Nrounds>55){                                                     \
    626         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    627         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    628     }                                                                   \
    629     if(Nrounds>55){                                                     \
    630         /* InjectKey(r=1) */                                            \
    631         X0 += ks4; X1 += ks0; X2 += ks1; X3 += ks2; \
    632         X3 += 14;     /* XWCNT4-1 += r  */                 \
    633     }                                                                   \
    634                                                                         \
    635     if(Nrounds>56){                                                     \
    636         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    637         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    638     }                                                                   \
    639     if(Nrounds>57){                                                     \
    640         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    641         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    642     }                                                                   \
    643     if(Nrounds>58){                                                     \
    644         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    645         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    646     }                                                                   \
    647     if(Nrounds>59){                                                     \
    648         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    649         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    650     }                                                                   \
    651     if(Nrounds>59){                                                     \
    652         /* InjectKey(r=1) */                                            \
    653         X0 += ks0; X1 += ks1; X2 += ks2; X3 += ks3; \
    654         X3 += 15;     /* XWCNT4-1 += r  */                 \
    655     }                                                                   \
    656                                                                         \
    657     if(Nrounds>60){                                                     \
    658         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    659         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    660     }                                                                   \
    661     if(Nrounds>61){                                                     \
    662         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    663         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    664     }                                                                   \
    665     if(Nrounds>62){                                                     \
    666         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    667         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    668     }                                                                   \
    669     if(Nrounds>63){                                                     \
    670         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    671         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    672     }                                                                   \
    673     if(Nrounds>63){                                                     \
    674         /* InjectKey(r=1) */                                            \
    675         X0 += ks1; X1 += ks2; X2 += ks3; X3 += ks4; \
    676         X3 += 16;     /* XWCNT4-1 += r  */                 \
    677     }                                                                   \
    678                                                                         \
    679     if(Nrounds>64){                                                     \
    680         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_0_0); X1 ^= X0; \
    681         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_0_1); X3 ^= X2; \
    682     }                                                                   \
    683     if(Nrounds>65){                                                     \
    684         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_1_0); X3 ^= X0; \
    685         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_1_1); X1 ^= X2; \
    686     }                                                                   \
    687     if(Nrounds>66){                                                     \
    688         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_2_0); X1 ^= X0; \
    689         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_2_1); X3 ^= X2; \
    690     }                                                                   \
    691     if(Nrounds>67){                                                     \
    692         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_3_0); X3 ^= X0; \
    693         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_3_1); X1 ^= X2; \
    694     }                                                                   \
    695     if(Nrounds>67){                                                     \
    696         /* InjectKey(r=1) */                                            \
    697         X0 += ks2; X1 += ks3; X2 += ks4; X3 += ks0; \
    698         X3 += 17;     /* XWCNT4-1 += r  */                 \
    699     }                                                                   \
    700                                                                         \
    701     if(Nrounds>68){                                                     \
    702         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_4_0); X1 ^= X0; \
    703         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_4_1); X3 ^= X2; \
    704     }                                                                   \
    705     if(Nrounds>69){                                                     \
    706         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_5_0); X3 ^= X0; \
    707         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_5_1); X1 ^= X2; \
    708     }                                                                   \
    709     if(Nrounds>70){                                                     \
    710         X0 += X1; X1 = RotL_##W(X1,R_##W##x4_6_0); X1 ^= X0; \
    711         X2 += X3; X3 = RotL_##W(X3,R_##W##x4_6_1); X3 ^= X2; \
    712     }                                                                   \
    713     if(Nrounds>71){                                                     \
    714         X0 += X3; X3 = RotL_##W(X3,R_##W##x4_7_0); X3 ^= X0; \
    715         X2 += X1; X1 = RotL_##W(X1,R_##W##x4_7_1); X1 ^= X2; \
    716     }                                                                   \
    717     if(Nrounds>71){                                                     \
    718         /* InjectKey(r=1) */                                            \
    719         X0 += ks3; X1 += ks4; X2 += ks0; X3 += ks1; \
    720         X3 += 18;     /* XWCNT4-1 += r  */                 \
    721     }                                                                   \
    722                                                                         \
    723     threefry4x##W##_ctr_t ret = {{X0, X1, X2, X3}}; \
    724     return ret;                                                           \
    725 }                                                                       \
    726                                                                         \
    727  /** @ingroup ThreefryNxW */                                            \
    728 enum r123_enum_threefry4x##W { threefry4x##W##_rounds = THREEFRY4x##W##_DEFAULT_ROUNDS };       \
    729 R123_CUDA_DEVICE R123_STATIC_INLINE R123_FORCE_INLINE(threefry4x##W##_ctr_t threefry4x##W(threefry4x##W##_ctr_t in, threefry4x##W##_key_t k)); \
    730 R123_CUDA_DEVICE R123_STATIC_INLINE                                     \
    731 threefry4x##W##_ctr_t threefry4x##W(threefry4x##W##_ctr_t in, threefry4x##W##_key_t k){ \
    732     return threefry4x##W##_R(threefry4x##W##_rounds, in, k);            \
    733 }
    734 
    735 #if R123_USE_64BIT
    736 _threefry2x_tpl(64)
    737 _threefry4x_tpl(64)
    738 #endif
    739 _threefry2x_tpl(32)
    740 _threefry4x_tpl(32)
    741 
    742 /* gcc4.5 and 4.6 seem to optimize a macro-ized threefryNxW better
    743    than a static inline function.  Why?  */
    744 #define threefry2x32(c,k) threefry2x32_R(threefry2x32_rounds, c, k)
    745 #define threefry4x32(c,k) threefry4x32_R(threefry4x32_rounds, c, k)
    746 #define threefry2x64(c,k) threefry2x64_R(threefry2x64_rounds, c, k)
    747 #define threefry4x64(c,k) threefry4x64_R(threefry4x64_rounds, c, k)
    748 
    749 #if defined(__cplusplus)
    750 #define _threefryNxWclass_tpl(NxW)                                      \
    751 namespace r123{                                                     \
    752 template<unsigned int ROUNDS>                                                  \
    753  struct Threefry##NxW##_R{                                              \
    754     typedef threefry##NxW##_ctr_t ctr_type;                             \
    755     typedef threefry##NxW##_key_t key_type;                             \
    756     typedef threefry##NxW##_key_t ukey_type;                            \
    757     static const R123_METAL_CONSTANT_ADDRESS_SPACE unsigned int rounds=ROUNDS;                            \
    758    inline R123_CUDA_DEVICE R123_FORCE_INLINE(ctr_type operator()(ctr_type ctr, key_type key)){ \
    759         R123_STATIC_ASSERT(ROUNDS<=72, "threefry is only unrolled up to 72 rounds\n"); \
    760         return threefry##NxW##_R(ROUNDS, ctr, key);                              \
    761     }                                                                   \
    762 };                                                                      \
    763  typedef Threefry##NxW##_R<threefry##NxW##_rounds> Threefry##NxW;       \
    764 } // namespace r123
    765 
    766 _threefryNxWclass_tpl(2x32)
    767 _threefryNxWclass_tpl(4x32)
    768 #if R123_USE_64BIT
    769 _threefryNxWclass_tpl(2x64)
    770 _threefryNxWclass_tpl(4x64)
    771 #endif
    772 
    773 /* The _tpl macros don't quite work to do string-pasting inside comments.
    774    so we just write out the boilerplate documentation four times... */
    775 
    776 /** 
    777 @defgroup ThreefryNxW Threefry Classes and Typedefs
    778 
    779 The ThreefryNxW classes export the member functions, typedefs and
    780 operator overloads required by a @ref CBRNG "CBRNG" class.
    781 
    782 As described in  
    783 <a href="http://dl.acm.org/citation.cfm?doid=2063405"><i>Parallel Random Numbers:  As Easy as 1, 2, 3</i> </a>, 
    784 the Threefry family is closely related to the Threefish block cipher from
    785 <a href="http://www.skein-hash.info/"> Skein Hash Function</a>.  
    786 Threefry is \b not suitable for cryptographic use.
    787 
    788 Threefry uses integer addition, bitwise rotation, xor and permutation of words to randomize its output.
    789 
    790 @class r123::Threefry2x32_R 
    791 @ingroup ThreefryNxW
    792 
    793 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    794 
    795 The template argument, ROUNDS, is the number of times the Threefry round
    796 function will be applied.
    797 
    798 As of September 2011, the authors know of no statistical flaws with
    799 ROUNDS=13 or more for Threefry2x32.
    800 
    801 @typedef r123::Threefry2x32
    802 @ingroup ThreefryNxW
    803   Threefry2x32 is equivalent to Threefry2x32_R<20>.    With 20 rounds,
    804   Threefry2x32 has a considerable safety margin over the minimum number
    805   of rounds with no known statistical flaws, but still has excellent
    806    performance. 
    807 
    808 @class r123::Threefry2x64_R 
    809 @ingroup ThreefryNxW
    810 
    811 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    812 
    813 The template argument, ROUNDS, is the number of times the Threefry round
    814 function will be applied.
    815 
    816 In November 2011, the authors discovered that 13 rounds of
    817 Threefry2x64 sequenced by strided, interleaved key and counter
    818 increments failed a very long (longer than the default BigCrush
    819 length) WeightDistrub test.  At the same time, it was confirmed that
    820 14 rounds passes much longer tests (up to 5x10^12 samples) of a
    821 similar nature.  The authors know of no statistical flaws with
    822 ROUNDS=14 or more for Threefry2x64.
    823 
    824 @typedef r123::Threefry2x64
    825 @ingroup ThreefryNxW
    826   Threefry2x64 is equivalent to Threefry2x64_R<20>.    With 20 rounds,
    827   Threefry2x64 has a considerable safety margin over the minimum number
    828   of rounds with no known statistical flaws, but still has excellent
    829    performance. 
    830 
    831 
    832 
    833 @class r123::Threefry4x32_R 
    834 @ingroup ThreefryNxW
    835 
    836 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    837 
    838 The template argument, ROUNDS, is the number of times the Threefry round
    839 function will be applied.
    840 
    841 As of September 2011, the authors know of no statistical flaws with
    842 ROUNDS=12 or more for Threefry4x32.
    843 
    844 @typedef r123::Threefry4x32
    845 @ingroup ThreefryNxW
    846   Threefry4x32 is equivalent to Threefry4x32_R<20>.    With 20 rounds,
    847   Threefry4x32 has a considerable safety margin over the minimum number
    848   of rounds with no known statistical flaws, but still has excellent
    849    performance. 
    850 
    851 
    852 
    853 @class r123::Threefry4x64_R 
    854 @ingroup ThreefryNxW
    855 
    856 exports the member functions, typedefs and operator overloads required by a @ref CBRNG "CBRNG" class.
    857 
    858 The template argument, ROUNDS, is the number of times the Threefry round
    859 function will be applied.
    860 
    861 As of September 2011, the authors know of no statistical flaws with
    862 ROUNDS=12 or more for Threefry4x64.
    863 
    864 @typedef r123::Threefry4x64
    865 @ingroup ThreefryNxW
    866   Threefry4x64 is equivalent to Threefry4x64_R<20>.    With 20 rounds,
    867   Threefry4x64 has a considerable safety margin over the minimum number
    868   of rounds with no known statistical flaws, but still has excellent
    869    performance. 
    870 */
    871 
    872 #endif
    873 
    874 #endif