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;}`;