Path: blob/master/sha3/sph_hefty1.c
1299 views
/*1* HEFTY1 cryptographic hash function2*3* Copyright (c) 2014, dbcc14 <BM-NBx4AKznJuyem3dArgVY8MGyABpihRy5>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions are met:8*9* 1. Redistributions of source code must retain the above copyright notice, this10* list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright notice,12* this list of conditions and the following disclaimer in the documentation13* and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED17* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE18* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR19* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES20* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;21* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND22* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT23* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS24* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.25*26* The views and conclusions contained in the software and documentation are those27* of the authors and should not be interpreted as representing official policies,28* either expressed or implied, of the FreeBSD Project.29*/3031#include <assert.h>32#include <string.h>3334#ifdef _MSC_VER35#define inline __inline36#endif3738#include "sph_hefty1.h"3940#define Min(A, B) (A <= B ? A : B)41#define RoundFunc(ctx, A, B, C, D, E, F, G, H, W, K) \42{ \43/* To thwart parallelism, Br modifies itself each time it's \44* called. This also means that calling it in different \45* orders yeilds different results. In C the order of \46* evaluation of function arguments and + operands are \47* unspecified (and depends on the compiler), so we must make \48* the order of Br calls explicit. \49*/ \50uint32_t brG = Br(ctx, G); \51uint32_t tmp1 = Ch(E, Br(ctx, F), brG) + H + W + K; \52uint32_t tmp2 = tmp1 + Sigma1(Br(ctx, E)); \53uint32_t brC = Br(ctx, C); \54uint32_t brB = Br(ctx, B); \55uint32_t tmp3 = Ma(Br(ctx, A), brB, brC); \56uint32_t tmp4 = tmp3 + Sigma0(Br(ctx, A)); \57H = G; \58G = F; \59F = E; \60E = D + Br(ctx, tmp2); \61D = C; \62C = B; \63B = A; \64A = tmp2 + tmp4; \65} \6667/* Nothing up my sleeve constants */68const static uint32_t K[64] = {690x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,700x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,710xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,720x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,730xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,740x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,750x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,760xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,770x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,780x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,790xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,800xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,810x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,820x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,830x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,840x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL85};8687/* Initial hash values */88const static uint32_t H[HEFTY1_STATE_WORDS] = {890x6a09e667UL,900xbb67ae85UL,910x3c6ef372UL,920xa54ff53aUL,930x510e527fUL,940x9b05688cUL,950x1f83d9abUL,960x5be0cd19UL97};9899static inline uint32_t Rr(uint32_t X, uint8_t n)100{101return (X >> n) | (X << (32 - n));102}103104static inline uint32_t Ch(uint32_t E, uint32_t F, uint32_t G)105{106return (E & F) ^ (~E & G);107}108109static inline uint32_t Sigma1(uint32_t E)110{111return Rr(E, 6) ^ Rr(E, 11) ^ Rr(E, 25);112}113114static inline uint32_t sigma1(uint32_t X)115{116return Rr(X, 17) ^ Rr(X, 19) ^ (X >> 10);117}118119static inline uint32_t Ma(uint32_t A, uint32_t B, uint32_t C)120{121return (A & B) ^ (A & C) ^ (B & C);122}123124static inline uint32_t Sigma0(uint32_t A)125{126return Rr(A, 2) ^ Rr(A, 13) ^ Rr(A, 22);127}128129static inline uint32_t sigma0(uint32_t X)130{131return Rr(X, 7) ^ Rr(X, 18) ^ (X >> 3);132}133134static inline uint32_t Reverse32(uint32_t n)135{136#if BYTE_ORDER == LITTLE_ENDIAN137return n << 24 | (n & 0x0000ff00) << 8 | (n & 0x00ff0000) >> 8 | n >> 24;138#else139return n;140#endif141}142143static inline uint64_t Reverse64(uint64_t n)144{145#if BYTE_ORDER == LITTLE_ENDIAN146uint32_t a = n >> 32;147uint32_t b = (n << 32) >> 32;148149return (uint64_t)Reverse32(b) << 32 | Reverse32(a);150#else151return n;152#endif153}154155/* Smoosh byte into nibble */156static inline uint8_t Smoosh4(uint8_t X)157{158return (X >> 4) ^ (X & 0xf);159}160161/* Smoosh 32-bit word into 2-bits */162static inline uint8_t Smoosh2(uint32_t X)163{164uint16_t w = (X >> 16) ^ (X & 0xffff);165uint8_t n = Smoosh4((w >> 8) ^ (w & 0xff));166return (n >> 2) ^ (n & 0x3);167}168169static void Mangle(uint32_t *S)170{171uint32_t *R = S;172uint32_t *C = &S[1];173174uint8_t r0 = Smoosh4(R[0] >> 24);175uint8_t r1 = Smoosh4(R[0] >> 16);176uint8_t r2 = Smoosh4(R[0] >> 8);177uint8_t r3 = Smoosh4(R[0] & 0xff);178179int i;180181/* Diffuse */182uint32_t tmp = 0;183for (i = 0; i < HEFTY1_SPONGE_WORDS - 1; i++) {184uint8_t r = Smoosh2(tmp);185switch (r) {186case 0:187C[i] ^= Rr(R[0], i + r0);188break;189case 1:190C[i] += Rr(~R[0], i + r1);191break;192case 2:193C[i] &= Rr(~R[0], i + r2);194break;195case 3:196C[i] ^= Rr(R[0], i + r3);197break;198}199tmp ^= C[i];200}201202/* Compress */203tmp = 0;204for (i = 0; i < HEFTY1_SPONGE_WORDS - 1; i++)205if (i % 2)206tmp ^= C[i];207else208tmp += C[i];209R[0] ^= tmp;210}211212static void Absorb(uint32_t *S, uint32_t X)213{214uint32_t *R = S;215R[0] ^= X;216Mangle(S);217}218219static uint32_t Squeeze(uint32_t *S)220{221uint32_t Y = S[0];222Mangle(S);223return Y;224}225226/* Branch, compress and serialize function */227static inline uint32_t Br(HEFTY1_CTX *ctx, uint32_t X)228{229uint32_t R = Squeeze(ctx->sponge);230231uint8_t r0 = R >> 8;232uint8_t r1 = R & 0xff;233234uint32_t Y = 1 << (r0 % 32);235236switch (r1 % 4)237{238case 0:239/* Do nothing */240break;241case 1:242return X & ~Y;243case 2:244return X | Y;245case 3:246return X ^ Y;247}248249return X;250}251252static void HashBlock(HEFTY1_CTX *ctx)253{254uint32_t A, B, C, D, E, F, G, H;255uint32_t W[HEFTY1_BLOCK_BYTES];256257assert(ctx);258259A = ctx->h[0];260B = ctx->h[1];261C = ctx->h[2];262D = ctx->h[3];263E = ctx->h[4];264F = ctx->h[5];265G = ctx->h[6];266H = ctx->h[7];267268int t = 0;269for (; t < 16; t++) {270W[t] = Reverse32(((uint32_t *)&ctx->block[0])[t]); /* To host byte order */271Absorb(ctx->sponge, W[t] ^ K[t]);272}273274for (t = 0; t < 16; t++) {275Absorb(ctx->sponge, D ^ H);276RoundFunc(ctx, A, B, C, D, E, F, G, H, W[t], K[t]);277}278for (t = 16; t < 64; t++) {279Absorb(ctx->sponge, H + D);280W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + W[t - 16];281RoundFunc(ctx, A, B, C, D, E, F, G, H, W[t], K[t]);282}283284ctx->h[0] += A;285ctx->h[1] += B;286ctx->h[2] += C;287ctx->h[3] += D;288ctx->h[4] += E;289ctx->h[5] += F;290ctx->h[6] += G;291ctx->h[7] += H;292293A = 0;294B = 0;295C = 0;296D = 0;297E = 0;298F = 0;299G = 0;300H = 0;301302memset(W, 0, sizeof(W));303}304305/* Public interface */306307void HEFTY1_Init(HEFTY1_CTX *ctx)308{309assert(ctx);310311memcpy(ctx->h, H, sizeof(ctx->h));312memset(ctx->block, 0, sizeof(ctx->block));313ctx->written = 0;314memset(ctx->sponge, 0, sizeof(ctx->sponge));315}316317void HEFTY1_Update(HEFTY1_CTX *ctx, const void *buf, size_t len)318{319assert(ctx);320321uint64_t read = 0;322while (len) {323size_t end = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES);324size_t count = Min(len, HEFTY1_BLOCK_BYTES - end);325memcpy(&ctx->block[end], &((unsigned char *)buf)[read], count);326len -= count;327read += count;328ctx->written += count;329if (!(ctx->written % HEFTY1_BLOCK_BYTES))330HashBlock(ctx);331}332}333334void HEFTY1_Final(unsigned char *digest, HEFTY1_CTX *ctx)335{336assert(digest);337assert(ctx);338339/* Pad message (FIPS 180 Section 5.1.1) */340size_t used = (size_t)(ctx->written % HEFTY1_BLOCK_BYTES);341ctx->block[used++] = 0x80; /* Append 1 to end of message */342if (used > HEFTY1_BLOCK_BYTES - 8) {343/* We have already written into the last 64bits, so344* we must continue into the next block. */345memset(&ctx->block[used], 0, HEFTY1_BLOCK_BYTES - used);346HashBlock(ctx);347used = 0; /* Create a new block (below) */348}349350/* All remaining bits to zero */351memset(&ctx->block[used], 0, HEFTY1_BLOCK_BYTES - 8 - used);352353/* The last 64bits encode the length (in network byte order) */354uint64_t *len = (uint64_t *)&ctx->block[HEFTY1_BLOCK_BYTES - 8];355*len = Reverse64(ctx->written*8);356357HashBlock(ctx);358359/* Convert back to network byte order */360int i = 0;361for (; i < HEFTY1_STATE_WORDS; i++)362ctx->h[i] = Reverse32(ctx->h[i]);363364memcpy(digest, ctx->h, sizeof(ctx->h));365memset(ctx, 0, sizeof(HEFTY1_CTX));366}367368unsigned char* HEFTY1(const unsigned char *buf, size_t len, unsigned char *digest)369{370HEFTY1_CTX ctx;371static unsigned char m[HEFTY1_DIGEST_BYTES];372373if (!digest)374digest = m;375376HEFTY1_Init(&ctx);377HEFTY1_Update(&ctx, buf, len);378HEFTY1_Final(digest, &ctx);379380return digest;381}382383