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 }