hash.c 1.29 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
  to_bit_interleaving_big_immediate(s.x0, 0x16d44c813b277eb5);
  to_bit_interleaving_big_immediate(s.x1, 0x2024ae622504512b);
  to_bit_interleaving_big_immediate(s.x2, 0x1822df8d76a7a366);
  to_bit_interleaving_big_immediate(s.x3, 0x0c6553817a0aad5a);
  to_bit_interleaving_big_immediate(s.x4, 0xb6939453320e3e4f);

  u32_2 t0;
  u64 tmp0;

  // absorb plaintext
  while (inlen >= RATE) {
    tmp0 = (*(u64*)in);
    t0 = to_bit_interleaving_big(tmp0);
    s.x0.e ^= t0.e;
    s.x0.o ^= t0.o;
    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_bit_interleaving_big(tmp[0]);
  s.x0.e ^= t0.e;
  s.x0.o ^= t0.o;

  P(&s, START_ROUND(PA_ROUNDS));

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

  return 0;
}