Botan  1.11.15
src/lib/block/serpent_simd/serp_simd.cpp
Go to the documentation of this file.
00001 /*
00002 * Serpent (SIMD)
00003 * (C) 2009,2013 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/block_utils.h>
00009 #include <botan/serp_simd.h>
00010 #include <botan/internal/serpent_sbox.h>
00011 #include <botan/internal/simd_32.h>
00012 
00013 namespace Botan {
00014 
00015 BOTAN_REGISTER_BLOCK_CIPHER_NOARGS_IF(SIMD_32::enabled(), Serpent_SIMD, "Serpent", "simd32", 64);
00016 
00017 namespace {
00018 
00019 #define key_xor(round, B0, B1, B2, B3)                             \
00020    do {                                                            \
00021       B0 ^= SIMD_32(keys[4*round  ]);                              \
00022       B1 ^= SIMD_32(keys[4*round+1]);                              \
00023       B2 ^= SIMD_32(keys[4*round+2]);                              \
00024       B3 ^= SIMD_32(keys[4*round+3]);                              \
00025    } while(0);
00026 
00027 /*
00028 * Serpent's linear transformations
00029 */
00030 #define transform(B0, B1, B2, B3)                                  \
00031    do {                                                            \
00032       B0.rotate_left(13);                                          \
00033       B2.rotate_left(3);                                           \
00034       B1 ^= B0 ^ B2;                                               \
00035       B3 ^= B2 ^ (B0 << 3);                                        \
00036       B1.rotate_left(1);                                           \
00037       B3.rotate_left(7);                                           \
00038       B0 ^= B1 ^ B3;                                               \
00039       B2 ^= B3 ^ (B1 << 7);                                        \
00040       B0.rotate_left(5);                                           \
00041       B2.rotate_left(22);                                          \
00042    } while(0);
00043 
00044 #define i_transform(B0, B1, B2, B3)                                \
00045    do {                                                            \
00046       B2.rotate_right(22);                                         \
00047       B0.rotate_right(5);                                          \
00048       B2 ^= B3 ^ (B1 << 7);                                        \
00049       B0 ^= B1 ^ B3;                                               \
00050       B3.rotate_right(7);                                          \
00051       B1.rotate_right(1);                                          \
00052       B3 ^= B2 ^ (B0 << 3);                                        \
00053       B1 ^= B0 ^ B2;                                               \
00054       B2.rotate_right(3);                                          \
00055       B0.rotate_right(13);                                         \
00056    } while(0);
00057 
00058 /*
00059 * SIMD Serpent Encryption of 4 blocks in parallel
00060 */
00061 void serpent_encrypt_4(const byte in[64],
00062                        byte out[64],
00063                        const u32bit keys[132])
00064    {
00065    SIMD_32 B0 = SIMD_32::load_le(in);
00066    SIMD_32 B1 = SIMD_32::load_le(in + 16);
00067    SIMD_32 B2 = SIMD_32::load_le(in + 32);
00068    SIMD_32 B3 = SIMD_32::load_le(in + 48);
00069 
00070    SIMD_32::transpose(B0, B1, B2, B3);
00071 
00072    key_xor( 0,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00073    key_xor( 1,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00074    key_xor( 2,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00075    key_xor( 3,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00076    key_xor( 4,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00077    key_xor( 5,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00078    key_xor( 6,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00079    key_xor( 7,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00080 
00081    key_xor( 8,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00082    key_xor( 9,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00083    key_xor(10,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00084    key_xor(11,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00085    key_xor(12,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00086    key_xor(13,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00087    key_xor(14,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00088    key_xor(15,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00089 
00090    key_xor(16,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00091    key_xor(17,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00092    key_xor(18,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00093    key_xor(19,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00094    key_xor(20,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00095    key_xor(21,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00096    key_xor(22,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00097    key_xor(23,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00098 
00099    key_xor(24,B0,B1,B2,B3); SBoxE1(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00100    key_xor(25,B0,B1,B2,B3); SBoxE2(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00101    key_xor(26,B0,B1,B2,B3); SBoxE3(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00102    key_xor(27,B0,B1,B2,B3); SBoxE4(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00103    key_xor(28,B0,B1,B2,B3); SBoxE5(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00104    key_xor(29,B0,B1,B2,B3); SBoxE6(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00105    key_xor(30,B0,B1,B2,B3); SBoxE7(B0,B1,B2,B3); transform(B0,B1,B2,B3);
00106    key_xor(31,B0,B1,B2,B3); SBoxE8(B0,B1,B2,B3); key_xor(32,B0,B1,B2,B3);
00107 
00108    SIMD_32::transpose(B0, B1, B2, B3);
00109 
00110    B0.store_le(out);
00111    B1.store_le(out + 16);
00112    B2.store_le(out + 32);
00113    B3.store_le(out + 48);
00114    }
00115 
00116 /*
00117 * SIMD Serpent Decryption of 4 blocks in parallel
00118 */
00119 void serpent_decrypt_4(const byte in[64],
00120                        byte out[64],
00121                        const u32bit keys[132])
00122    {
00123    SIMD_32 B0 = SIMD_32::load_le(in);
00124    SIMD_32 B1 = SIMD_32::load_le(in + 16);
00125    SIMD_32 B2 = SIMD_32::load_le(in + 32);
00126    SIMD_32 B3 = SIMD_32::load_le(in + 48);
00127 
00128    SIMD_32::transpose(B0, B1, B2, B3);
00129 
00130    key_xor(32,B0,B1,B2,B3);  SBoxD8(B0,B1,B2,B3); key_xor(31,B0,B1,B2,B3);
00131    i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(30,B0,B1,B2,B3);
00132    i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(29,B0,B1,B2,B3);
00133    i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(28,B0,B1,B2,B3);
00134    i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(27,B0,B1,B2,B3);
00135    i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(26,B0,B1,B2,B3);
00136    i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(25,B0,B1,B2,B3);
00137    i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(24,B0,B1,B2,B3);
00138 
00139    i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(23,B0,B1,B2,B3);
00140    i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(22,B0,B1,B2,B3);
00141    i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(21,B0,B1,B2,B3);
00142    i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(20,B0,B1,B2,B3);
00143    i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(19,B0,B1,B2,B3);
00144    i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(18,B0,B1,B2,B3);
00145    i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor(17,B0,B1,B2,B3);
00146    i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor(16,B0,B1,B2,B3);
00147 
00148    i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor(15,B0,B1,B2,B3);
00149    i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor(14,B0,B1,B2,B3);
00150    i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor(13,B0,B1,B2,B3);
00151    i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor(12,B0,B1,B2,B3);
00152    i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor(11,B0,B1,B2,B3);
00153    i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor(10,B0,B1,B2,B3);
00154    i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 9,B0,B1,B2,B3);
00155    i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 8,B0,B1,B2,B3);
00156 
00157    i_transform(B0,B1,B2,B3); SBoxD8(B0,B1,B2,B3); key_xor( 7,B0,B1,B2,B3);
00158    i_transform(B0,B1,B2,B3); SBoxD7(B0,B1,B2,B3); key_xor( 6,B0,B1,B2,B3);
00159    i_transform(B0,B1,B2,B3); SBoxD6(B0,B1,B2,B3); key_xor( 5,B0,B1,B2,B3);
00160    i_transform(B0,B1,B2,B3); SBoxD5(B0,B1,B2,B3); key_xor( 4,B0,B1,B2,B3);
00161    i_transform(B0,B1,B2,B3); SBoxD4(B0,B1,B2,B3); key_xor( 3,B0,B1,B2,B3);
00162    i_transform(B0,B1,B2,B3); SBoxD3(B0,B1,B2,B3); key_xor( 2,B0,B1,B2,B3);
00163    i_transform(B0,B1,B2,B3); SBoxD2(B0,B1,B2,B3); key_xor( 1,B0,B1,B2,B3);
00164    i_transform(B0,B1,B2,B3); SBoxD1(B0,B1,B2,B3); key_xor( 0,B0,B1,B2,B3);
00165 
00166    SIMD_32::transpose(B0, B1, B2, B3);
00167 
00168    B0.store_le(out);
00169    B1.store_le(out + 16);
00170    B2.store_le(out + 32);
00171    B3.store_le(out + 48);
00172    }
00173 
00174 }
00175 
00176 #undef key_xor
00177 #undef transform
00178 #undef i_transform
00179 
00180 /*
00181 * Serpent Encryption
00182 */
00183 void Serpent_SIMD::encrypt_n(const byte in[], byte out[], size_t blocks) const
00184    {
00185    const u32bit* KS = &(this->get_round_keys()[0]);
00186 
00187    while(blocks >= 4)
00188       {
00189       serpent_encrypt_4(in, out, KS);
00190       in += 4 * BLOCK_SIZE;
00191       out += 4 * BLOCK_SIZE;
00192       blocks -= 4;
00193       }
00194 
00195    if(blocks)
00196      Serpent::encrypt_n(in, out, blocks);
00197    }
00198 
00199 /*
00200 * Serpent Decryption
00201 */
00202 void Serpent_SIMD::decrypt_n(const byte in[], byte out[], size_t blocks) const
00203    {
00204    const u32bit* KS = &(this->get_round_keys()[0]);
00205 
00206    while(blocks >= 4)
00207       {
00208       serpent_decrypt_4(in, out, KS);
00209       in += 4 * BLOCK_SIZE;
00210       out += 4 * BLOCK_SIZE;
00211       blocks -= 4;
00212       }
00213 
00214    if(blocks)
00215      Serpent::decrypt_n(in, out, blocks);
00216    }
00217 
00218 }