static ERL_NIF_TERM context_fini(ErlNifEnv* env, Context* ctx, size_t dsize, ChunkHandler handler) { ERL_NIF_TERM result; ctx->bitlen += ctx->count*8; pad(0, 0, ctx); handler(ctx, ctx->bytes); if (ctx->count > ctx->size) { handler(ctx, ctx->bytes + ctx->size); } #ifndef WORDS_BIGENDIAN { int i; if (ctx->size == PADDED_SIZE_2XX_BYTES) { uint32_t* hash = (uint32_t*)ctx->digest.data; for (i = 0; i < ctx->digest.size/sizeof(*hash); ++i) { hash[i] = BYTESWAP32(hash[i]); } } else { uint64_t* hash = (uint64_t*)ctx->digest.data; for (i = 0; i < ctx->digest.size/sizeof(*hash); ++i) { hash[i] = BYTESWAP64(hash[i]); } } } #endif if (ctx->digest.size != dsize) { enif_realloc_binary(&ctx->digest, dsize); } result = enif_make_binary(env, &ctx->digest); ctx->digest.size = 0; return result; }
static void pad(unsigned char* bin, uint64_t binsize, Context* ctx) { unsigned char* p; uint64_t congruence = ctx->size == PADDED_SIZE_2XX_BYTES ? CONGRUENCE_2XX : CONGRUENCE_5XX; uint64_t lenbits = ctx->bitlen; uint64_t pad; while (lenbits + 1 > congruence) { congruence += ctx->size*8; } pad = (congruence - (lenbits + 1)) / 8; if (ctx->size == PADDED_SIZE_5XX_BYTES) { pad += 8; } if (bin != NULL && binsize > 0) { memcpy(ctx->bytes + ctx->count, bin, binsize); ctx->count += binsize; } p = ctx->bytes + ctx->count; *p++ = 0x80; memset(p, 0, pad); #ifndef WORDS_BIGENDIAN *(uint64_t*)(p + pad) = BYTESWAP64(lenbits); #else *(uint64_t*)(p + pad) = lenbits; #endif ctx->count += 1 + pad + sizeof lenbits; }
void reverse(char *bytes, int numChunks) { uint64_t *arr = (uint64_t *)bytes; uint64_t buf[BUF_SIZE]; for (int j = 0; j < numChunks; ++j) { memcpy(buf, arr + BUF_SIZE * j, BUF_SIZE * sizeof(uint64_t)); for (int i = 0; i < BUF_SIZE; ++i) buf[i] = BYTESWAP64(buf[i]); for (int i = 0; i < BUF_SIZE / 2; ++i) { uint64_t tmp = buf[i]; buf[i] = buf[BUF_SIZE - i - 1]; buf[BUF_SIZE - i - 1] = tmp; } memcpy(arr + BUF_SIZE * j, buf, BUF_SIZE * sizeof(uint64_t)); } }
static void sha5xx_chunk(Context* ctx, unsigned char* chunk) { uint64_t* hash = (uint64_t*)ctx->digest.data; uint64_t a, b, c, d, e, f, g, h; uint64_t words[80]; int i; #ifndef WORDS_BIGENDIAN { uint64_t* from = (uint64_t*)chunk; for (i = 0; i < 16; ++i) { words[i] = BYTESWAP64(from[i]); } } #else memcpy(words, chunk, 16*sizeof(*words)); #endif for (i = 16; i < sizeof(words)/sizeof(*words); ++i) { uint64_t w15 = words[i-15], w2 = words[i-2]; uint64_t s0 = SM_SIGMA512_0(w15), s1 = SM_SIGMA512_1(w2); uint64_t w7 = words[i-7], w16 = words[i-16]; words[i] = s1 + w7 + s0 + w16; } a = hash[0]; b = hash[1]; c = hash[2]; d = hash[3]; e = hash[4]; f = hash[5]; g = hash[6]; h = hash[7]; for (i = 0; i < sizeof(words)/sizeof(*words); ++i) { uint64_t t1, t2; t1 = h + BIG_SIGMA512_1(e) + CH(e,f,g) + K512[i] + words[i]; t2 = BIG_SIGMA512_0(a) + MAJ(a,b,c); h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; } hash[0] += a; hash[1] += b; hash[2] += c; hash[3] += d; hash[4] += e; hash[5] += f; hash[6] += g; hash[7] += h; }