threefish-0.1: cbits/skein256.c
#include "threefish.h"
#include <string.h>
void skein256_init(skein_t* ctx, W64* key, int outlen) {
W64 config[4] = {0x0000000133414853, outlen*8, 0, 0};
static W64 zeroes[4] = {0,0,0,0};
/* Set up key if needed */
if(key != NULL) {
init_tweak(T_KEY, ctx->tweak);
set_last(1, ctx->tweak);
add_bytes(32, ctx->tweak);
encrypt256(zeroes, ctx->tweak[0], ctx->tweak[1], key, ctx->key);
ctx->key[0] ^= key[0];
ctx->key[1] ^= key[1];
ctx->key[2] ^= key[2];
ctx->key[3] ^= key[3];
} else {
ctx->key[0] = 0; ctx->key[1] = 0; ctx->key[2] = 0; ctx->key[3] = 0;
}
/* Process config string */
mk_config_tweak(ctx->tweak);
add_bytes(32, ctx->tweak);
encrypt256(ctx->key, ctx->tweak[0], ctx->tweak[1], config, ctx->key);
ctx->key[0] ^= config[0];
ctx->key[1] ^= config[1];
ctx->key[2] ^= config[2];
ctx->key[3] ^= config[3];
}
void skein256_update(skein_t* ctx, int firstlast, UBIType type, W64 len, W64* data) {
W64 buf[4] = {0,0,0,0};
W64* k = ctx->key;
W64* tweak = ctx->tweak;
int lastlen;
/* Process message */
if(firstlast & 1) {
init_tweak(type, tweak);
}
/* If this is not the last update, don't do last block processing */
if(!(firstlast & 2) && len % 32 == 0) {
++len;
}
while(len > 32) {
add_bytes(32, tweak);
encrypt256(k, tweak[0], tweak[1], data, k);
set_first(0, tweak);
k[0] ^= *data; ++data;
k[1] ^= *data; ++data;
k[2] ^= *data; ++data;
k[3] ^= *data; ++data;
len -= 32;
}
/* Process last block */
if(firstlast & 2) {
lastlen = len % 32;
if(lastlen == 0 && len > 0) {
lastlen = 32;
}
add_bytes(lastlen, tweak);
set_last(1, tweak);
memcpy(buf, data, lastlen);
encrypt256(k, tweak[0], tweak[1], buf, k);
k[0] ^= buf[0];
k[1] ^= buf[1];
k[2] ^= buf[2];
k[3] ^= buf[3];
}
}
void skein256_output(skein_t* ctx, int from, int to, W64* out) {
W64 buf[4] = {from,0,0,0};
W64 *k = ctx->key;
W64 *tweak = ctx->tweak;
for(; from <= to; ++from) {
init_tweak(T_OUT, tweak);
set_last(1, tweak);
add_bytes(8, tweak);
encrypt256(k, tweak[0], tweak[1], buf, out);
out += 4;
++buf[0];
}
}
void hash256(W64* key, W64* nonce, W64 len, W64* data, int outlen, W64* out) {
skein_t ctx;
skein256_init(&ctx, key, outlen);
/* Process nonce, if available; must be 32 bytes */
if(nonce != NULL) {
skein256_update(&ctx, 3, T_NONCE, 32, nonce);
}
skein256_update(&ctx, 3, T_MSG, len, data);
if(outlen % 32 == 0) {
outlen = outlen / 32;
} else {
outlen = (outlen / 32) + 1;
}
skein256_output(&ctx, 0, outlen, out);
}