1 module dcrypt.aead.gcm.galoisfield;
2 
3 import std.traits: isIntegral;
4 
5 package:
6 @safe
7 struct GF128
8 {
9 
10 	alias ubyte	T;
11 	alias T[BLOCKLEN/(T.sizeof*8)]	block;
12 
13 	enum BLOCKLEN = 128;
14 
15 	enum T R = 0xE1<<(T.sizeof*8-8);
16 
17 	enum T ONE = 0x80<<(T.sizeof*8-8);
18 
19 	/**
20 	 * raises x to the power 'pow' by squaring
21 	 * x <- x^pow
22 	 * 
23 	 * Params:
24 	 * x = this value gets raised to the power pow
25 	 * pow = the power
26 	 */
27 	static void power(T)(T[] x, ulong pow) nothrow @nogc
28 		if(isIntegral!T)
29 		in {
30 			assert(x.length*T.sizeof*8 == BLOCKLEN, "invalid length. expected 16 bytes.");
31 		}
32 	body {
33 		block squared;
34 		squared[] = x[];
35 
36 		block exp;
37 		exp[0] = ONE; // little endian 1
38 
39 		block one;
40 		one[0] = ONE; // little endian 1
41 
42 		while(pow > 0) {
43 
44 			if(pow & 0x1) {
45 				multiply(exp, squared);
46 			} else {
47 				multiply(exp, one);	// dummy multiplication to avoid timing attacks
48 			}
49 
50 			multiply(squared, squared);
51 
52 			pow = pow >> 1;
53 		}
54 		
55 		x[] = exp[];
56 	}
57 
58 	// test power
59 	unittest {
60 		immutable ubyte[] x = cast(immutable ubyte[]) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
61 
62 		ubyte[16] naivePow;
63 		naivePow[0] = 0x80; // little endian 1
64 
65 		immutable uint pow = 13;
66 
67 		for(uint i = 0; i < pow; ++i) {
68 			multiply(naivePow, x);
69 		}
70 
71 		ubyte[16] powBySquare;
72 		powBySquare[] = x[];
73 
74 		power(powBySquare, pow);
75 
76 		assert(naivePow == powBySquare, "power() failed");
77 	}
78 
79 	/// Multiplies x by y using schoolbook multiplication. Result stored in x.
80 	static void multiply(T[] x, in T[] y) nothrow @nogc
81 	in {
82 		assert(x.length*T.sizeof*8 == BLOCKLEN, "x: invalid length.");
83 	}
84 	body {
85 
86 		block v = x;
87 		block z;
88 
89 		for(uint i = 0; i < y.length; ++i) {
90 			T currWord = y[i];
91 
92 			for(int j = T.sizeof*8-1; j >= 0; --j) {
93 
94 				//				if((currWord >> j) & 0x01) {
95 				//					z[] ^= v[];
96 				//				}
97 				// avoid branching:
98 				z[] ^= v[]&(-(cast(T)((currWord >> j) & 1))); // less prone to timing attacks than if statement
99 
100 				T lsb = v[$-1] & 1;
101 				shiftRight(v);
102 
103 				//				if(lsb) {
104 				//					v[0] ^= R;
105 				//				}
106 				// Avoid branching by using conditional XOR:
107 				v[0] ^= R&(-lsb); // -lsb is either 0x00, or 0xFF
108 			}
109 		}
110 
111 		x[] = z[];
112 	}
113 
114 	/// test multiplication by one
115 	unittest {
116 		immutable block x0 = cast(immutable block) x"66e94bd4ef8a2c3b884cfa59ca342b2e";
117 		block x1 = x0;
118 
119 		block one;
120 		one[0] = ONE;
121 		
122 		multiply(x1, one);
123 		
124 		assert(x1 == x0, "GCM multiplication by ONE failed!");
125 	}
126 
127 	/// test multiplication
128 	unittest {
129 
130 		immutable block H = cast(immutable block)x"66e94bd4ef8a2c3b884cfa59ca342b2e";
131 
132 		block x1 = cast(immutable block) x"0388dace60b6a392f328c2b971b2fe78";
133 
134 		multiply(x1, H);
135 		
136 		assert(x1 == x"5e2ec746917062882c85b0685353deb7", "GCM multiplication failed!");
137 	}
138 
139 	// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
140 	unittest {
141 
142 		immutable block H = cast(immutable block) x"73A23D80121DE2D5A850253FCF43120E";
143 		block X1 = cast(immutable block) x"D609B1F056637A0D46DF998D88E5222A";
144 		
145 		multiply(X1, H);
146 
147 		assert(X1 == x"6B0BE68D67C6EE03EF7998E399C01CA4", "GCM multiplication failed!");
148 	}
149 
150 	// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
151 	unittest {
152 		
153 		immutable block H = cast(immutable block) x"286D73994EA0BA3CFD1F52BF06A8ACF2";
154 		block X1 = cast(immutable block) x"D609B1F056637A0D46DF998D88E5222A";
155 		
156 		multiply(X1, H);
157 		
158 		assert(X1 == x"BA7C26F578254853CF321281A48317CA", "GCM multiplication failed!");
159 	}
160 
161 	// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
162 	unittest {
163 		
164 		immutable block H = cast(immutable block) x"E4E01725D724C1215C7309AD34539257";
165 		block X1 = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
166 		
167 		multiply(X1, H);
168 
169 		assert(X1 == x"8DAD4981E33493018BB8482F69E4478C", "GCM multiplication failed!");
170 	}
171 
172 	/**
173 	 * multiplication by P (only bit 1 = 1)
174 	 */
175 	static void multiplyP(T[] x) nothrow @nogc
176 	in {
177 		assert(x.length == 16, "x: invalid length. must be 16.");
178 	}
179 	body {
180 		T lsb = x[$-1] & 0x01;
181 		shiftRight(x);
182 		x[0] ^= R * lsb;
183 	}
184 
185 	// test multiplyP()
186 	unittest {
187 
188 		block X = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
189 		immutable block P = cast(immutable block) x"40000000000000000000000000000000";
190 
191 		block XmultP;
192 		XmultP = X;
193 
194 		multiplyP(XmultP);
195 
196 		multiply(X, P);
197 
198 		assert(X == XmultP, "multiplyP() failed");
199 	}
200 
201 	/**
202 	 * multiplication by P^8
203 	 */
204 	static void multiplyP8(T)(T[] x)
205 	{
206 		T lsw = x[$-1];
207 		shiftRight8(x);
208 		for (int i = 7; i >= 0; --i)
209 		{
210 			//			if (lsw & (1 << i))
211 			//			{
212 			//				x[0] ^= ((R<<(T.sizeof*8-8)) >> (7 - i));
213 			//			}
214 			//			avoid branching:
215 			x[0] ^= (((R<<(T.sizeof*8-8)) >> (7 - i))) * (lsw & (1 << i));
216 		}
217 	}
218 
219 	// test multiplyP8()
220 	unittest {
221 		
222 		block X = cast(immutable block) x"E20106D7CD0DF0761E8DCD3D88E54000";
223 		immutable block P = cast(immutable block) x"40000000000000000000000000000000";
224 
225 		block XmultP8;
226 		XmultP8 = X;
227 		
228 		multiplyP8(XmultP8);
229 
230 		foreach(i;0..8){
231 			multiply(X, P);
232 		}
233 		
234 		assert(X == XmultP8, "multiplyP8() failed");
235 	}
236 	
237 	/**
238 	 * Shift big endian number a 1 bit to the right.
239 	 */
240 	static void shiftRight(T)(T[] a) nothrow @nogc 
241 		if(isIntegral!T)
242 	{
243 		T carryBit = 0;
244 		for(size_t i = 0; i < a.length; ++i) {
245 			T b = a[i];
246 			a[i] >>= 1;
247 			a[i] |= carryBit;
248 			carryBit = cast(T)(b << (T.sizeof * 8 - 1));
249 		}
250 	}
251 
252 	// test right shift with bytes
253 	unittest {
254 		ubyte[] a = [0xf1,0x83,0x01];
255 		shiftRight(a);
256 		assert(a == [0x78,0xc1,0x80], "right shift failed");
257 	}
258 
259 	// test shiftRight
260 	unittest {
261 		
262 		ubyte[16] a = cast(immutable ubyte[16]) x"59ed3f2bb1a0aaa07c9f56c6a504647b";
263 		foreach(i;0..8) {
264 			shiftRight(a);
265 		}
266 		
267 		assert(a == x"0059ed3f2bb1a0aaa07c9f56c6a50464", "right shift failed");
268 	}
269 
270 	// with ints
271 	unittest {
272 		uint[] a = [0xfedcba98,0x76543210];
273 		foreach(i;0..8) {
274 			shiftRight(a);
275 		}
276 		assert(a == [0x00fedcba,0x98765432], "right shift failed");
277 	}
278 
279 	// with longs
280 	unittest {
281 		ulong[] a = [0x59ed3f2bb1a0aaa0,0x7c9f56c6a504647b];
282 		foreach(i;0..8) {
283 			shiftRight(a);
284 		}
285 		assert(a == [0x0059ed3f2bb1a0aa,0xa07c9f56c6a50464], "right shift failed");
286 	}
287 
288 	/**
289 	 * Shift big endian number a 8 bits to the right.
290 	 */
291 	static void shiftRight8(T)(T[] a) nothrow @nogc {
292 		T carryBit = 0;
293 		for(size_t i = 0; i < a.length; ++i) {
294 			T b = a[i];
295 			a[i] >>= 8;
296 			a[i] |= carryBit;
297 			carryBit = cast(T)(b << (T.sizeof * 8 - 8));
298 		}
299 	}
300 
301 	//	static void shiftRight(T)(T[] a, ubyte n) nothrow @nogc {
302 	//		T carryBit = 0;
303 	//		for(size_t i = 0; i < a.length; ++i) {
304 	//			T b = a[i];
305 	//			a[i] >>= n;
306 	//			a[i] |= carryBit;
307 	//			carryBit = cast(T)(b << (T.sizeof * 8 - n));
308 	//		}
309 	//	}
310 
311 	
312 	//	static void shiftRight(ubyte[] a, ubyte n) nothrow @nogc {
313 	//		shiftRight(cast(uint[])a, n);
314 	//	}
315 
316 	// test shiftRight8()
317 	unittest {
318 		ubyte[16] a = cast(immutable ubyte[16])x"59ed3f2bb1a0aaa07c9f56c6a504647b";
319 		ubyte[16] b = a;
320 		foreach(i;0..8) {
321 			shiftRight(a);
322 		}
323 
324 		shiftRight8(b);
325 		
326 		assert(a == b, "right shift by 8 bits failed");
327 	}
328 
329 }