hash.c 1.15 KB
Newer Older
Ferdinand Bachmann committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#include <string.h>
#include "api.h"
#include "endian.h"
#include "permutations.h"

#define RATE (64 / 8)
#define PA_ROUNDS 12

int crypto_hash(unsigned char* out, const unsigned char* in,
                unsigned long long inlen) {
  state s;
  u64 outlen;

  // initialization
  s.x0.h = 0xb57e273b; s.x0.l = 0x814cd416;
  s.x1.h = 0x2b510425; s.x1.l = 0x62ae2420;
  s.x2.h = 0x66a3a776; s.x2.l = 0x8ddf2218;
  s.x3.h = 0x5aad0a7a; s.x3.l = 0x8153650c;
  s.x4.h = 0x4f3e0e32; s.x4.l = 0x539493b6;

  u32_2 t0;
  u64 tmp0;

  // absorb plaintext
  while (inlen >= RATE) {
    tmp0 = (*(u64*)in);
    t0 = to_big(tmp0);
    s.x0.h ^= t0.h;
    s.x0.l ^= t0.l;
    P(&s, START_ROUND(PA_ROUNDS));
    inlen -= RATE;
    in += RATE;
  }

  u8 bytes[16];
  memcpy(bytes, in, inlen);
  memset(bytes + inlen, 0, 16 - inlen);
  bytes[inlen] ^= 0x80;

  u64* tmp = (u64*)bytes;

  t0 = to_big(tmp[0]);
  s.x0.h ^= t0.h;
  s.x0.l ^= t0.l;

  P(&s, START_ROUND(PA_ROUNDS));

  // squeeze hash
  outlen = CRYPTO_BYTES;
  while (outlen >= RATE) {
    tmp0 = from_big(s.x0);
    *(u64*)out = tmp0;
    P(&s, START_ROUND(PA_ROUNDS));
    outlen -= RATE;
    out += RATE;
  }

  return 0;
}