upstream: https://github.com/mirage/mirage-crypto
at main 110 lines 3.4 kB view raw
1/* Copyright (c) 2017 David Kaloper Meršinjak. All rights reserved. 2 See LICENSE.md. */ 3 4#include "crypto.h" 5#include <string.h> 6 7/* Generic table-driven GHASH. 8 * 9 * References: 10 * - The Galois/Counter Mode of Operation. David A. McGrew and John Viega. 11 * - NIST SP 800-38D. Recommendation for Block Cipher Modes of Operation: 12 * Galois/Counter Mode (GCM) and GMAC. 13 */ 14 15/* LARGE_TABLES -> 65K per key 16 * !LARGE_TABLES -> 8K per key, ~3x slower. */ 17#define __MC_GHASH_LARGE_TABLES 18 19/* 64-bit Windows sets ARCH_64BIT but 128-bit integers are not supported 20 * by the Microsoft compiler. Drop down to 32-bit for MSVC; 21 * ghash_ctmul.c will implement ghash for MSVC. 22 */ 23#if defined(ARCH_64BIT) && !defined(_MSC_VER) 24 25#define __set_uint128_t(w1, w0) (((__uint128_t) w1 << 64) | w0) 26 27static const __uint128_t r = __set_uint128_t (0xe100000000000000, 0); 28 29static inline __uint128_t __load_128_t (const uint64_t s[2]) { 30 return __set_uint128_t (be64_to_cpu (s[0]), be64_to_cpu (s[1])); 31} 32 33static inline __uint128_t __load_128_t_with_padding (const uint8_t *src, size_t n) { 34 uint64_t buf[2] = { 0 }; 35 memcpy (buf, src, n); 36 return __load_128_t (buf); 37} 38 39static inline void __store_128_t (uint64_t s[2], __uint128_t x) { 40 s[0] = cpu_to_be64 (x >> 64); 41 s[1] = cpu_to_be64 (x); 42} 43 44#if defined (__MC_GHASH_LARGE_TABLES) 45#define __t_width 8 // coefficient window 46#define __t_tables 16 // 128 / t_width 47#define __t_size 4096 // 2^t_width * t_tables 48#else 49#define __t_width 4 50#define __t_tables 32 51#define __t_size 512 52#endif 53 54static inline __uint128_t __gfmul (__uint128_t a, __uint128_t b) { 55 __uint128_t z = 0, 56 v = a; 57 for (int i = 0; i < 128; i ++) { 58 if ((uint64_t) (b >> (127 - i)) & 1) 59 z = z ^ v; 60 v = (uint64_t) v & 1 ? (v >> 1) ^ r : v >> 1; 61 } 62 return z; 63} 64 65// NB Exponents are reversed. 66// TODO: Fast table derivation. 67static inline void __derive (uint64_t key[2], __uint128_t m[__t_size]) { 68 __uint128_t e = 1 << (__t_width - 1), 69 h = __load_128_t (key); 70 for (int i = 0; i < __t_tables; i ++, e <<= __t_width) { 71 __uint128_t exph = __gfmul (h, e); 72 for (int j = 0; j < (1 << __t_width); j ++) 73 m[(i << __t_width) | j] = __gfmul (exph, (__uint128_t) j << (128 - __t_width)); 74 } 75} 76 77#define __t_mask ((1 << __t_width) - 1) 78static inline __uint128_t __gfmul_tab (__uint128_t m[__t_size], __uint128_t x) { 79 __uint128_t r = 0; 80 for (int i = 0; i < __t_tables; i ++) 81 r ^= m[(i << __t_width) | ((uint8_t) (x >> (i * __t_width)) & __t_mask)]; 82 return r; 83} 84 85static inline void __ghash (__uint128_t m[__t_size], uint64_t hash[2], const uint8_t *src, size_t n) { 86 __uint128_t acc = __load_128_t (hash); 87 for (; n >= 16; src += 16, n -= 16) 88 acc = __gfmul_tab (m, acc ^ __load_128_t ((uint64_t *) src)); 89 if (n > 0) 90 acc = __gfmul_tab (m, acc ^ __load_128_t_with_padding (src, n)); 91 __store_128_t (hash, acc); 92} 93 94CAMLprim value mc_ghash_key_size_generic (__unit ()) { 95 return Val_int (sizeof (__uint128_t) * __t_size); 96} 97 98CAMLprim value mc_ghash_init_key_generic (value key, value m) { 99 __derive ((uint64_t *) _st_uint8 (key), (__uint128_t *) Bp_val (m)); 100 return Val_unit; 101} 102 103CAMLprim value 104mc_ghash_generic (value m, value hash, value src, value off, value len) { 105 __ghash ((__uint128_t *) Bp_val (m), (uint64_t *) Bp_val (hash), 106 _st_uint8_off (src, off), Int_val (len) ); 107 return Val_unit; 108} 109 110#endif /* ARCH_64BIT */