1 /** 2 * Noekeon in SIMD 3 * 4 * Copyright: 5 * (C) 2010 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.noekeon_simd; 12 13 import botan.constants; 14 static if (BOTAN_HAS_NOEKEON_SIMD): 15 16 import botan.block.noekeon; 17 import botan.block.block_cipher; 18 import botan.utils.loadstor; 19 import botan.simd.simd_32; 20 import botan.utils.mem_ops; 21 22 /** 23 * Noekeon implementation using SIMD operations 24 */ 25 final class NoekeonSIMD : Noekeon 26 { 27 public: 28 override @property size_t parallelism() const { return 4; } 29 30 /* 31 * Noekeon Encryption 32 */ 33 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 34 { 35 const SecureVector!uint* EK = &this.getEK(); 36 37 SIMD32 K0 = SIMD32((*EK)[0]); 38 SIMD32 K1 = SIMD32((*EK)[1]); 39 SIMD32 K2 = SIMD32((*EK)[2]); 40 SIMD32 K3 = SIMD32((*EK)[3]); 41 42 while (blocks >= 4) 43 { 44 SIMD32 A0 = SIMD32.loadBigEndian(input ); 45 SIMD32 A1 = SIMD32.loadBigEndian(input + 16); 46 SIMD32 A2 = SIMD32.loadBigEndian(input + 32); 47 SIMD32 A3 = SIMD32.loadBigEndian(input + 48); 48 49 SIMD32.transpose(A0, A1, A2, A3); 50 51 foreach (size_t i; 0 .. 16) 52 { 53 A0 ^= SIMD32(cast(uint) m_RC[i]); 54 55 mixin(NOK_SIMD_THETA); 56 57 A1.rotateLeft!1(); 58 A2.rotateLeft!5(); 59 A3.rotateLeft!2(); 60 61 mixin(NOK_SIMD_GAMMA); 62 63 A1.rotateRight!1(); 64 A2.rotateRight!5(); 65 A3.rotateRight!2(); 66 } 67 68 A0 ^= SIMD32(cast(uint) m_RC[16]); 69 mixin(NOK_SIMD_THETA); 70 71 SIMD32.transpose(A0, A1, A2, A3); 72 73 A0.storeBigEndian(output); 74 A1.storeBigEndian(output + 16); 75 A2.storeBigEndian(output + 32); 76 A3.storeBigEndian(output + 48); 77 78 input += 64; 79 output += 64; 80 blocks -= 4; 81 } 82 83 if (blocks) 84 super.encryptN(input, output, blocks); 85 } 86 87 /* 88 * Noekeon Encryption 89 */ 90 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 91 { 92 const SecureVector!uint* DK = &this.getDK(); 93 94 SIMD32 K0 = SIMD32((*DK)[0]); 95 SIMD32 K1 = SIMD32((*DK)[1]); 96 SIMD32 K2 = SIMD32((*DK)[2]); 97 SIMD32 K3 = SIMD32((*DK)[3]); 98 99 while (blocks >= 4) 100 { 101 SIMD32 A0 = SIMD32.loadBigEndian(input ); 102 SIMD32 A1 = SIMD32.loadBigEndian(input + 16); 103 SIMD32 A2 = SIMD32.loadBigEndian(input + 32); 104 SIMD32 A3 = SIMD32.loadBigEndian(input + 48); 105 106 SIMD32.transpose(A0, A1, A2, A3); 107 108 foreach (size_t i; 0 .. 16) 109 { 110 mixin(NOK_SIMD_THETA); 111 112 A0 ^= SIMD32(cast(uint) m_RC[16-i]); 113 114 A1.rotateLeft!1(); 115 A2.rotateLeft!5(); 116 A3.rotateLeft!2(); 117 118 mixin(NOK_SIMD_GAMMA); 119 120 A1.rotateRight!1(); 121 A2.rotateRight!5(); 122 A3.rotateRight!2(); 123 } 124 125 mixin(NOK_SIMD_THETA); 126 A0 ^= SIMD32(cast(uint) m_RC[0]); 127 128 SIMD32.transpose(A0, A1, A2, A3); 129 130 A0.storeBigEndian(output); 131 A1.storeBigEndian(output + 16); 132 A2.storeBigEndian(output + 32); 133 A3.storeBigEndian(output + 48); 134 135 input += 64; 136 output += 64; 137 blocks -= 4; 138 } 139 140 if (blocks) 141 super.decryptN(input, output, blocks); 142 } 143 144 override BlockCipher clone() const { return new NoekeonSIMD; } 145 } 146 147 /* 148 * Noekeon's Theta Operation 149 */ 150 enum string NOK_SIMD_THETA = 151 `{SIMD32 T = A0 ^ A2; 152 SIMD32 T_l8 = T; 153 SIMD32 T_r8 = T; 154 T_l8.rotateLeft!8(); 155 T_r8.rotateRight!8(); 156 T ^= T_l8; 157 T ^= T_r8; 158 A1 ^= T; 159 A3 ^= T; 160 A0 ^= K0; 161 A1 ^= K1; 162 A2 ^= K2; 163 A3 ^= K3; 164 T = A1 ^ A3; 165 T_l8 = T; 166 T_r8 = T; 167 T_l8.rotateLeft!8(); 168 T_r8.rotateRight!8(); 169 T ^= T_l8; 170 T ^= T_r8; 171 A0 ^= T; 172 A2 ^= T;}`; 173 174 /* 175 * Noekeon's Gamma S-Box Layer 176 */ 177 enum string NOK_SIMD_GAMMA = 178 `{A1 ^= A3.andc(~A2); 179 A0 ^= A2 & A1; 180 SIMD32 T = A3; 181 A3 = A0; 182 A0 = T; 183 A2 ^= A0 ^ A1 ^ A3; 184 A1 ^= A3.andc(~A2); 185 A0 ^= A2 & A1;}`;