keccak-fast.c

Minimal SIMD keccak implementation
git clone git://git.finwo.net/lib/keccak-fast.c
Log | Files | Refs | README | LICENSE

keccak-fast.c (4722B)


      1 #include "keccak-fast.h"
      2 
      3 #include <string.h>
      4 
      5 #include "keccak-fast-internal.h"
      6 
      7 #define KF_RATE(bits) (200 - ((bits) / 4))
      8 #define KF_DOMAIN_SHAKE 0x1f
      9 #define KF_DOMAIN_SHA3  0x06
     10 
     11 kf_hash_fn kf_shake128 = kf_scalar_shake128;
     12 kf_hash_fn kf_shake256 = kf_scalar_shake256;
     13 kf_hash_fn kf_sha3_224 = kf_scalar_sha3_224;
     14 kf_hash_fn kf_sha3_256 = kf_scalar_sha3_256;
     15 kf_hash_fn kf_sha3_384 = kf_scalar_sha3_384;
     16 kf_hash_fn kf_sha3_512 = kf_scalar_sha3_512;
     17 kf_hash_fn kf_turboshake128 = kf_scalar_turboshake128;
     18 kf_hash_fn kf_turboshake256 = kf_scalar_turboshake256;
     19 
     20 int         kf_backend_priority = KF_PRIO_SCALAR;
     21 const char *kf_backend_label    = "scalar";
     22 
     23 kf_batch_perm_fn kf_batch_perm     = kf_scalar_batch;
     24 kf_batch_perm_fn kf_batch_perm12   = kf_scalar_batch12;
     25 int              kf_batch_priority = KF_PRIO_SCALAR;
     26 int              kf_batch_lanes    = 1;
     27 const char      *kf_batch_label    = "scalar";
     28 
     29 const char *kf_backend_name(void) {
     30   return kf_backend_label;
     31 }
     32 
     33 const char *kf_batch_name(void) {
     34   return kf_batch_label;
     35 }
     36 
     37 static void kf_wipe(void *p, size_t n) {
     38   static void *(*const volatile fn)(void *, int, size_t) = memset;
     39   fn(p, 0, n);
     40 }
     41 
     42 static void kf_sponge_group(kf_batch_perm_fn perm, const uint8_t *in,
     43                             size_t inlen, uint8_t *out, size_t outlen,
     44                             size_t base, size_t count, size_t rate,
     45                             uint8_t delim) {
     46   uint64_t       states[KF_LANES_MAX][25] = {0};
     47   uint8_t       *a                        = (uint8_t *)states;
     48   const uint8_t *p[KF_LANES_MAX];
     49   uint8_t       *o[KF_LANES_MAX];
     50 
     51   for (size_t i = 0; i < count; i++) {
     52     p[i] = in + (base + i) * inlen;
     53     o[i] = out + (base + i) * outlen;
     54   }
     55 
     56   size_t remaining = inlen;
     57   while (remaining >= rate) {
     58     for (size_t i = 0; i < count; i++) {
     59       for (size_t j = 0; j < rate; j++) a[i * 200 + j] ^= p[i][j];
     60       p[i] += rate;
     61     }
     62     perm(states, count);
     63     remaining -= rate;
     64   }
     65 
     66   for (size_t i = 0; i < count; i++) {
     67     for (size_t j = 0; j < remaining; j++) a[i * 200 + j] ^= p[i][j];
     68     a[i * 200 + remaining] ^= delim;
     69     a[i * 200 + rate - 1] ^= 0x80;
     70   }
     71   perm(states, count);
     72 
     73   size_t outrem = outlen;
     74   while (outrem >= rate) {
     75     for (size_t i = 0; i < count; i++) {
     76       memcpy(o[i], a + i * 200, rate);
     77       o[i] += rate;
     78     }
     79     outrem -= rate;
     80     perm(states, count);
     81   }
     82   for (size_t i = 0; i < count; i++) {
     83     memcpy(o[i], a + i * 200, outrem);
     84   }
     85 
     86   kf_wipe(states, sizeof states);
     87 }
     88 
     89 static int kf_batch_impl(kf_hash_fn one, kf_batch_perm_fn perm, size_t count,
     90                          const uint8_t *in, size_t inlen, uint8_t *out,
     91                          size_t outlen, size_t rate, uint8_t delim) {
     92   if (count == 0) return 0;
     93   if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= 200)) return -1;
     94 
     95   int lanes = kf_batch_lanes;
     96   if (lanes > KF_LANES_MAX) lanes = KF_LANES_MAX;
     97 
     98   size_t base = 0;
     99   if (lanes > 1) {
    100     size_t l = (size_t)lanes;
    101     for (; base + l <= count; base += l) {
    102       kf_sponge_group(perm, in, inlen, out, outlen, base, l, rate, delim);
    103     }
    104   }
    105   for (; base < count; base++) {
    106     one(out + base * outlen, outlen, in + base * inlen, inlen);
    107   }
    108   return 0;
    109 }
    110 
    111 #define KF_DEFSHAKE_BATCH(bits)                                                \
    112   int kf_shake##bits##_batch(size_t count, const uint8_t *in, size_t inlen,    \
    113                              uint8_t *out, size_t outlen) {                    \
    114     return kf_batch_impl(kf_shake##bits, kf_batch_perm, count, in, inlen, out, \
    115                          outlen, KF_RATE(bits), KF_DOMAIN_SHAKE);              \
    116   }
    117 #define KF_DEFSHA3_BATCH(bits)                                                 \
    118   int kf_sha3_##bits##_batch(size_t count, const uint8_t *in, size_t inlen,    \
    119                              uint8_t *out, size_t outlen) {                    \
    120     if (outlen > ((bits) / 8)) return -1;                                      \
    121     return kf_batch_impl(kf_sha3_##bits, kf_batch_perm, count, in, inlen, out, \
    122                          outlen, KF_RATE(bits), KF_DOMAIN_SHA3);               \
    123   }
    124 #define KF_DEFTURBOSHAKE_BATCH(bits)                                           \
    125   int kf_turboshake##bits##_batch(size_t count, const uint8_t *in,             \
    126                                   size_t inlen, uint8_t *out, size_t outlen) { \
    127     return kf_batch_impl(kf_turboshake##bits, kf_batch_perm12, count, in,      \
    128                          inlen, out, outlen, KF_RATE(bits), KF_DOMAIN_SHAKE);  \
    129   }
    130 
    131 KF_DEFSHAKE_BATCH(128)
    132 KF_DEFSHAKE_BATCH(256)
    133 KF_DEFSHA3_BATCH(224)
    134 KF_DEFSHA3_BATCH(256)
    135 KF_DEFSHA3_BATCH(384)
    136 KF_DEFSHA3_BATCH(512)
    137 KF_DEFTURBOSHAKE_BATCH(128)
    138 KF_DEFTURBOSHAKE_BATCH(256)