Blame cbits/hs_sha256.h

Packit f46cda
/*
Packit f46cda
 * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>
Packit f46cda
 *               2016      Herbert Valerio Riedel <hvr@gnu.org>
Packit f46cda
 *
Packit f46cda
 * Redistribution and use in source and binary forms, with or without
Packit f46cda
 * modification, are permitted provided that the following conditions
Packit f46cda
 * are met:
Packit f46cda
 * 1. Redistributions of source code must retain the above copyright
Packit f46cda
 *    notice, this list of conditions and the following disclaimer.
Packit f46cda
 * 2. Redistributions in binary form must reproduce the above copyright
Packit f46cda
 *    notice, this list of conditions and the following disclaimer in the
Packit f46cda
 *    documentation and/or other materials provided with the distribution.
Packit f46cda
 *
Packit f46cda
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit f46cda
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit f46cda
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit f46cda
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit f46cda
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
Packit f46cda
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit f46cda
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit f46cda
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit f46cda
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Packit f46cda
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit f46cda
 */
Packit f46cda
Packit f46cda
#ifndef HS_CRYPTOHASH_SHA256_H
Packit f46cda
#define HS_CRYPTOHASH_SHA256_H
Packit f46cda
Packit f46cda
#include <stdint.h>
Packit f46cda
#include <stddef.h>
Packit f46cda
#include <assert.h>
Packit f46cda
#include <string.h>
Packit f46cda
#include <ghcautoconf.h>
Packit f46cda
Packit f46cda
struct sha256_ctx
Packit f46cda
{
Packit f46cda
  uint64_t sz;
Packit f46cda
  uint8_t  buf[64];
Packit f46cda
  uint32_t h[8];
Packit f46cda
};
Packit f46cda
Packit f46cda
/* keep this synchronised with 'digestSize'/'sizeCtx' in SHA256.hs */
Packit f46cda
#define SHA256_DIGEST_SIZE	32
Packit f46cda
#define SHA256_CTX_SIZE		104
Packit f46cda
Packit f46cda
static inline void hs_cryptohash_sha256_init (struct sha256_ctx *ctx);
Packit f46cda
static inline void hs_cryptohash_sha256_update (struct sha256_ctx *ctx, const uint8_t *data, size_t len);
Packit f46cda
static inline uint64_t hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out);
Packit f46cda
Packit f46cda
#if defined(static_assert)
Packit f46cda
static_assert(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE, "unexpected sha256_ctx size");
Packit f46cda
#else
Packit f46cda
/* poor man's pre-C11 _Static_assert */
Packit f46cda
typedef char static_assertion__unexpected_sha256_ctx_size[(sizeof(struct sha256_ctx) == SHA256_CTX_SIZE)?1:-1];
Packit f46cda
#endif
Packit f46cda
Packit f46cda
#define ptr_uint32_aligned(ptr) (!((uintptr_t)(ptr) & 0x3))
Packit f46cda
Packit f46cda
static inline uint32_t
Packit f46cda
ror32(const uint32_t word, const unsigned shift)
Packit f46cda
{
Packit f46cda
  /* GCC usually transforms this into a 'ror'-insn */
Packit f46cda
  return (word >> shift) | (word << (32 - shift));
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline uint32_t
Packit f46cda
cpu_to_be32(const uint32_t hl)
Packit f46cda
{
Packit f46cda
#if WORDS_BIGENDIAN
Packit f46cda
  return hl;
Packit f46cda
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
Packit f46cda
  return __builtin_bswap32(hl);
Packit f46cda
#else
Packit f46cda
  /* GCC usually transforms this into a bswap insn */
Packit f46cda
  return ((hl & 0xff000000) >> 24) |
Packit f46cda
         ((hl & 0x00ff0000) >> 8)  |
Packit f46cda
         ((hl & 0x0000ff00) << 8)  |
Packit f46cda
         ( hl               << 24);
Packit f46cda
#endif
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline void
Packit f46cda
cpu_to_be32_array(uint32_t *dest, const uint32_t *src, unsigned wordcnt)
Packit f46cda
{
Packit f46cda
  while (wordcnt--)
Packit f46cda
    *dest++ = cpu_to_be32(*src++);
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline uint64_t
Packit f46cda
cpu_to_be64(const uint64_t hll)
Packit f46cda
{
Packit f46cda
#if WORDS_BIGENDIAN
Packit f46cda
  return hll;
Packit f46cda
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
Packit f46cda
  return __builtin_bswap64(hll);
Packit f46cda
#else
Packit f46cda
  return ((uint64_t)cpu_to_be32(hll & 0xffffffff) << 32LL) | cpu_to_be32(hll >> 32);
Packit f46cda
#endif
Packit f46cda
}
Packit f46cda
Packit f46cda
Packit f46cda
static inline void
Packit f46cda
hs_cryptohash_sha256_init (struct sha256_ctx *ctx)
Packit f46cda
{
Packit f46cda
  memset(ctx, 0, SHA256_CTX_SIZE);
Packit f46cda
Packit f46cda
  ctx->h[0] = 0x6a09e667;
Packit f46cda
  ctx->h[1] = 0xbb67ae85;
Packit f46cda
  ctx->h[2] = 0x3c6ef372;
Packit f46cda
  ctx->h[3] = 0xa54ff53a;
Packit f46cda
  ctx->h[4] = 0x510e527f;
Packit f46cda
  ctx->h[5] = 0x9b05688c;
Packit f46cda
  ctx->h[6] = 0x1f83d9ab;
Packit f46cda
  ctx->h[7] = 0x5be0cd19;
Packit f46cda
}
Packit f46cda
Packit f46cda
/* 232 times the cube root of the first 64 primes 2..311 */
Packit f46cda
static const uint32_t k[] = {
Packit f46cda
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
Packit f46cda
  0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
Packit f46cda
  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
Packit f46cda
  0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
Packit f46cda
  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
Packit f46cda
  0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
Packit f46cda
  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
Packit f46cda
  0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
Packit f46cda
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
Packit f46cda
  0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
Packit f46cda
  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
Packit f46cda
};
Packit f46cda
Packit f46cda
#define e0(x)       (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22))
Packit f46cda
#define e1(x)       (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25))
Packit f46cda
#define s0(x)       (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3))
Packit f46cda
#define s1(x)       (ror32(x,17) ^ ror32(x,19) ^ (x >> 10))
Packit f46cda
Packit f46cda
static void
Packit f46cda
sha256_do_chunk_aligned(struct sha256_ctx *ctx, uint32_t w[])
Packit f46cda
{
Packit f46cda
  int i;
Packit f46cda
Packit f46cda
  for (i = 16; i < 64; i++)
Packit f46cda
    w[i] = s1(w[i - 2]) + w[i - 7] + s0(w[i - 15]) + w[i - 16];
Packit f46cda
Packit f46cda
  uint32_t a = ctx->h[0];
Packit f46cda
  uint32_t b = ctx->h[1];
Packit f46cda
  uint32_t c = ctx->h[2];
Packit f46cda
  uint32_t d = ctx->h[3];
Packit f46cda
  uint32_t e = ctx->h[4];
Packit f46cda
  uint32_t f = ctx->h[5];
Packit f46cda
  uint32_t g = ctx->h[6];
Packit f46cda
  uint32_t h = ctx->h[7];
Packit f46cda
Packit f46cda
#define R(a, b, c, d, e, f, g, h, k, w)             \
Packit f46cda
    t1 = h + e1(e) + (g ^ (e & (f ^ g))) + k + w;   \
Packit f46cda
    t2 = e0(a) + ((a & b) | (c & (a | b)));         \
Packit f46cda
    d += t1;                                        \
Packit f46cda
    h = t1 + t2;
Packit f46cda
Packit f46cda
  for (i = 0; i < 64; i += 8) {
Packit f46cda
    uint32_t t1, t2;
Packit f46cda
Packit f46cda
    R(a, b, c, d, e, f, g, h, k[i + 0], w[i + 0]);
Packit f46cda
    R(h, a, b, c, d, e, f, g, k[i + 1], w[i + 1]);
Packit f46cda
    R(g, h, a, b, c, d, e, f, k[i + 2], w[i + 2]);
Packit f46cda
    R(f, g, h, a, b, c, d, e, k[i + 3], w[i + 3]);
Packit f46cda
    R(e, f, g, h, a, b, c, d, k[i + 4], w[i + 4]);
Packit f46cda
    R(d, e, f, g, h, a, b, c, k[i + 5], w[i + 5]);
Packit f46cda
    R(c, d, e, f, g, h, a, b, k[i + 6], w[i + 6]);
Packit f46cda
    R(b, c, d, e, f, g, h, a, k[i + 7], w[i + 7]);
Packit f46cda
  }
Packit f46cda
Packit f46cda
#undef R
Packit f46cda
Packit f46cda
  ctx->h[0] += a;
Packit f46cda
  ctx->h[1] += b;
Packit f46cda
  ctx->h[2] += c;
Packit f46cda
  ctx->h[3] += d;
Packit f46cda
  ctx->h[4] += e;
Packit f46cda
  ctx->h[5] += f;
Packit f46cda
  ctx->h[6] += g;
Packit f46cda
  ctx->h[7] += h;
Packit f46cda
}
Packit f46cda
Packit f46cda
static void
Packit f46cda
sha256_do_chunk(struct sha256_ctx *ctx, const uint8_t buf[])
Packit f46cda
{
Packit f46cda
  uint32_t w[64]; /* only first 16 words are filled in */
Packit f46cda
  if (ptr_uint32_aligned(buf)) { /* aligned buf */
Packit f46cda
    cpu_to_be32_array(w, (const uint32_t *)buf, 16);
Packit f46cda
  } else { /* unaligned buf */
Packit f46cda
    memcpy(w, buf, 64);
Packit f46cda
#if !WORDS_BIGENDIAN
Packit f46cda
    cpu_to_be32_array(w, w, 16);
Packit f46cda
#endif
Packit f46cda
  }
Packit f46cda
  sha256_do_chunk_aligned(ctx, w);
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline void
Packit f46cda
hs_cryptohash_sha256_update(struct sha256_ctx *ctx, const uint8_t *data, size_t len)
Packit f46cda
{
Packit f46cda
  size_t index = ctx->sz & 0x3f;
Packit f46cda
  const size_t to_fill = 64 - index;
Packit f46cda
Packit f46cda
  ctx->sz += len;
Packit f46cda
Packit f46cda
  /* process partial buffer if there's enough data to make a block */
Packit f46cda
  if (index && len >= to_fill) {
Packit f46cda
    memcpy(ctx->buf + index, data, to_fill);
Packit f46cda
    sha256_do_chunk(ctx, ctx->buf);
Packit f46cda
    /* memset(ctx->buf, 0, 64); */
Packit f46cda
    len -= to_fill;
Packit f46cda
    data += to_fill;
Packit f46cda
    index = 0;
Packit f46cda
  }
Packit f46cda
Packit f46cda
  /* process as many 64-blocks as possible */
Packit f46cda
  while (len >= 64) {
Packit f46cda
    sha256_do_chunk(ctx, data);
Packit f46cda
    len -= 64;
Packit f46cda
    data += 64;
Packit f46cda
  }
Packit f46cda
Packit f46cda
  /* append data into buf */
Packit f46cda
  if (len)
Packit f46cda
    memcpy(ctx->buf + index, data, len);
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline uint64_t
Packit f46cda
hs_cryptohash_sha256_finalize (struct sha256_ctx *ctx, uint8_t *out)
Packit f46cda
{
Packit f46cda
  static const uint8_t padding[64] = { 0x80, };
Packit f46cda
  const uint64_t sz = ctx->sz;
Packit f46cda
Packit f46cda
  /* add padding and update data with it */
Packit f46cda
  uint64_t bits = cpu_to_be64(ctx->sz << 3);
Packit f46cda
Packit f46cda
  /* pad out to 56 */
Packit f46cda
  const size_t index = ctx->sz & 0x3f;
Packit f46cda
  const size_t padlen = (index < 56) ? (56 - index) : ((64 + 56) - index);
Packit f46cda
  hs_cryptohash_sha256_update(ctx, padding, padlen);
Packit f46cda
Packit f46cda
  /* append length */
Packit f46cda
  hs_cryptohash_sha256_update(ctx, (uint8_t *) &bits, sizeof(bits));
Packit f46cda
Packit f46cda
  /* output hash */
Packit f46cda
  cpu_to_be32_array((uint32_t *) out, ctx->h, 8);
Packit f46cda
Packit f46cda
  return sz;
Packit f46cda
}
Packit f46cda
Packit f46cda
static inline void
Packit f46cda
hs_cryptohash_sha256_hash (const uint8_t *data, size_t len, uint8_t *out)
Packit f46cda
{
Packit f46cda
  struct sha256_ctx ctx;
Packit f46cda
Packit f46cda
  hs_cryptohash_sha256_init(&ctx;;
Packit f46cda
Packit f46cda
  hs_cryptohash_sha256_update(&ctx, data, len);
Packit f46cda
Packit f46cda
  hs_cryptohash_sha256_finalize(&ctx, out);
Packit f46cda
}
Packit f46cda
Packit f46cda
#endif