/*
* threefish.c
* Copyright 2010 Jonathan Bowman
* macro-based unrolled version (c) 2014,2018 Bernd Paysan
* Added threefish-256 in 2018
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include <string.h>
#include <stdio.h>
#include "threefish.h"
#include "skein.h"
static const uint8_t tf_rot_256[] = {
14, 16,
52, 57,
23, 40,
5, 37,
25, 33,
46, 12,
58, 22,
32, 32,
};
static const uint8_t tf_perm_256[] = {
0, 1, 2, 3,
0, 3, 2, 1,
0, 1, 2, 3,
0, 3, 2, 1,
};
static const uint8_t tf_rot_512[] = {
46, 36, 19, 37,
33, 27, 14, 42,
17, 49, 36, 39,
44, 9, 54, 56,
39, 30, 34, 24,
13, 50, 10, 17,
25, 29, 39, 43,
8, 35, 56, 22
};
static const uint8_t tf_perm_512[] = {
0,1,2,3,4,5,6,7,
2,1,4,7,6,5,0,3,
4,1,6,3,0,5,2,7,
6,1,0,7,2,5,4,3
};
/* 64-bit rotate left */
static inline uint64_t rot_l64(uint64_t x, uint16_t N)
{
return (x << N) ^ (x >> (64-N));
}
/* 64-bit rotate right */
static inline uint64_t rot_r64(uint64_t x, uint16_t N) {
return (x >> N) ^ (x << (64-N));
}
static inline void tf_prep_256(struct tf_ctx_256 *ctx)
{
ctx->key[4] = ctx->key[0] ^ ctx->key[1] ^ ctx->key[2] ^
ctx->key[3] ^ SKEIN_KS_PARITY;
}
static inline void tf_prep_512(struct tf_ctx_512 *ctx)
{
ctx->key[8] = ctx->key[0] ^ ctx->key[1] ^ ctx->key[2] ^
ctx->key[3] ^ ctx->key[4] ^ ctx->key[5] ^
ctx->key[6] ^ ctx->key[7] ^ SKEIN_KS_PARITY;
}
static inline void tf_tweak_256(struct tf_ctx_256 *ctx)
{
ctx->tweak[2] = ctx->tweak[0] ^ ctx->tweak[1];
}
static inline void tf_tweak_512(struct tf_ctx_512 *ctx)
{
ctx->tweak[2] = ctx->tweak[0] ^ ctx->tweak[1];
}
#define PERMUTE_256(i) \
m = tf_perm_256[2*i]; \
n = tf_perm_256[2*i+1]; \
X[m] += X[n]; \
X[n] = X[m] ^ rot_l64(X[n], tf_rot_256[i+s]);
#define TWEAKE_256(r) \
for (y=0;y<4;y++) \
X[y] += ctx->key[(r+y) % 5]; \
X[1] += ctx->tweak[(r) % 3]; \
X[2] += ctx->tweak[(r+1) % 3]; \
X[3] += r
#define ROUNDE_256(r) \
PERMUTE_256(0); PERMUTE_256(1); PERMUTE_256(2); PERMUTE_256(3); \
PERMUTE_256(4); PERMUTE_256(5); PERMUTE_256(6); PERMUTE_256(7); \
TWEAKE_256(r); s ^= 8
void tf_encrypt_256(struct tf_ctx_256 *ctx, const uint64_t *p,
uint64_t *out, int flags)
{
uint64_t X[4];
int8_t i,m,n,s=0,y;
if(flags & 8) {
tf_prep_256(ctx);
}
if(flags & 4) {
tf_tweak_256(ctx);
}
for(i=0;i<4;i++) {
X[i] = p[i] + ctx->key[i];
}
X[1] += ctx->tweak[0];
X[2] += ctx->tweak[1];
/* The rounds: */
ROUNDE_256(1); ROUNDE_256(2); ROUNDE_256(3); ROUNDE_256(4); ROUNDE_256(5); ROUNDE_256(6);
ROUNDE_256(7); ROUNDE_256(8); ROUNDE_256(9); ROUNDE_256(10); ROUNDE_256(11); ROUNDE_256(12);
ROUNDE_256(13); ROUNDE_256(14); ROUNDE_256(15); ROUNDE_256(16); ROUNDE_256(17); ROUNDE_256(18);
switch(flags & 3) {
case 2: // Bernd mode, fall through to ECB mode
for (i=0; i<4; i++) {
ctx->key[i] ^= X[i] ^ p[i];
}
case 0: // ECB mode
memmove(out, X, 32);
break;
case 1: // SKEIN mode
for (i=0; i<4; i++) {
out[i] = X[i] ^ p[i];
} break;
default: break;
}
}
#define PERMUTE_512(i) \
m = tf_perm_512[2*i]; \
n = tf_perm_512[2*i+1]; \
X[m] += X[n]; \
X[n] = X[m] ^ rot_l64(X[n], tf_rot_512[i+s]);
#define TWEAKE_512(r) \
for (y=0;y<8;y++) \
X[y] += ctx->key[(r+y) % 9]; \
X[5] += ctx->tweak[(r) % 3]; \
X[6] += ctx->tweak[(r+1) % 3]; \
X[7] += r
#define ROUNDE_512(r) \
PERMUTE_512(0); PERMUTE_512(1); PERMUTE_512(2); PERMUTE_512(3); \
PERMUTE_512(4); PERMUTE_512(5); PERMUTE_512(6); PERMUTE_512(7); \
PERMUTE_512(8); PERMUTE_512(9); PERMUTE_512(10); PERMUTE_512(11); \
PERMUTE_512(12); PERMUTE_512(13); PERMUTE_512(14); PERMUTE_512(15); \
TWEAKE_512(r); s ^= 16
void tf_encrypt_512(struct tf_ctx_512 *ctx, const uint64_t *p,
uint64_t *out, int flags)
{
uint64_t X[8];
int8_t i,m,n,s=0,y;
if(flags & 8) {
tf_prep_512(ctx);
}
if(flags & 4) {
tf_tweak_512(ctx);
}
for(i=0;i<8;i++) {
X[i] = p[i] + ctx->key[i];
}
X[5] += ctx->tweak[0];
X[6] += ctx->tweak[1];
/* The rounds: */
ROUNDE_512(1); ROUNDE_512(2); ROUNDE_512(3); ROUNDE_512(4); ROUNDE_512(5); ROUNDE_512(6);
ROUNDE_512(7); ROUNDE_512(8); ROUNDE_512(9); ROUNDE_512(10); ROUNDE_512(11); ROUNDE_512(12);
ROUNDE_512(13); ROUNDE_512(14); ROUNDE_512(15); ROUNDE_512(16); ROUNDE_512(17); ROUNDE_512(18);
switch(flags & 3) {
case 2: // Bernd mode, fall through to ECB mode
for (i=0; i<8; i++) {
ctx->key[i] ^= X[i] ^ p[i];
}
case 0: // ECB mode
memmove(out, X, 64);
break;
case 1: // SKEIN mode
for (i=0; i<8; i++) {
out[i] = X[i] ^ p[i];
} break;
default: break;
}
}
#define PERMUTD_256(i) \
m = tf_perm_256[2*i]; \
n = tf_perm_256[2*i+1]; \
X[n] = rot_r64(X[m]^X[n], tf_rot_256[i+s]); \
X[m] -= X[n]
#define TWEAKD_256(r) \
for (y=0;y<4;y++) { \
X[y] -= ctx->key[(r+y) % 5]; \
} \
X[1] -= ctx->tweak[(r) % 3]; \
X[2] -= ctx->tweak[(r+1) % 3]; \
X[3] -= r;
#define ROUNDD_256(r) \
TWEAKD_256(r); \
PERMUTD_256(7); PERMUTD_256(6); PERMUTD_256(5); PERMUTD_256(4); \
PERMUTD_256(3); PERMUTD_256(2); PERMUTD_256(1); PERMUTD_256(0); \
s ^= 8;
void tf_decrypt_256(struct tf_ctx_256 *ctx, const uint64_t *c, uint64_t *out, int flags)
{
uint64_t X[4];
int8_t i,m,n,s=8,y;
if(flags & 8) {
tf_prep_256(ctx);
}
if(flags & 4) {
tf_tweak_256(ctx);
}
memmove(X, c, 32);
/* The rounds: */
ROUNDD_256(18); ROUNDD_256(17); ROUNDD_256(16); ROUNDD_256(15); ROUNDD_256(14); ROUNDD_256(13);
ROUNDD_256(12); ROUNDD_256(11); ROUNDD_256(10); ROUNDD_256(9); ROUNDD_256(8); ROUNDD_256(7);
ROUNDD_256(6); ROUNDD_256(5); ROUNDD_256(4); ROUNDD_256(3); ROUNDD_256(2); ROUNDD_256(1);
for (i=0; i<4; i++) {
X[i] -= ctx->key[i];
}
X[1] -= ctx->tweak[0];
X[2] -= ctx->tweak[1];
switch(flags & 3) {
case 2: // Bernd mode, fall through to ECB mode
for (i=0; i<4; i++) {
ctx->key[i] ^= X[i] ^ c[i];
}
case 0: // ECB mode
memmove(out, X, 32);
break;
default: break;
}
}
#define PERMUTD_512(i) \
m = tf_perm_512[2*i]; \
n = tf_perm_512[2*i+1]; \
X[n] = rot_r64(X[m]^X[n], tf_rot_512[i+s]); \
X[m] -= X[n]
#define TWEAKD_512(r) \
for (y=0;y<8;y++) { \
X[y] -= ctx->key[(r+y) % 9]; \
} \
X[5] -= ctx->tweak[(r) % 3]; \
X[6] -= ctx->tweak[(r+1) % 3]; \
X[7] -= r;
#define ROUNDD_512(r) \
TWEAKD_512(r); \
PERMUTD_512(15); PERMUTD_512(14); PERMUTD_512(13); PERMUTD_512(12); \
PERMUTD_512(11); PERMUTD_512(10); PERMUTD_512(9); PERMUTD_512(8); \
PERMUTD_512(7); PERMUTD_512(6); PERMUTD_512(5); PERMUTD_512(4); \
PERMUTD_512(3); PERMUTD_512(2); PERMUTD_512(1); PERMUTD_512(0); \
s ^= 16;
void tf_decrypt_512(struct tf_ctx_512 *ctx, const uint64_t *c, uint64_t *out, int flags)
{
uint64_t X[8];
int8_t i,m,n,s=16,y;
if(flags & 8) {
tf_prep_512(ctx);
}
if(flags & 4) {
tf_tweak_512(ctx);
}
memmove(X, c, 64);
/* The rounds: */
ROUNDD_512(18); ROUNDD_512(17); ROUNDD_512(16); ROUNDD_512(15); ROUNDD_512(14); ROUNDD_512(13);
ROUNDD_512(12); ROUNDD_512(11); ROUNDD_512(10); ROUNDD_512(9); ROUNDD_512(8); ROUNDD_512(7);
ROUNDD_512(6); ROUNDD_512(5); ROUNDD_512(4); ROUNDD_512(3); ROUNDD_512(2); ROUNDD_512(1);
for (i=0; i<8; i++) {
X[i] -= ctx->key[i];
}
X[5] -= ctx->tweak[0];
X[6] -= ctx->tweak[1];
switch(flags & 3) {
case 2: // Bernd mode, fall through to ECB mode
for (i=0; i<8; i++) {
ctx->key[i] ^= X[i] ^ c[i];
}
case 0: // ECB mode
memmove(out, X, 64);
break;
default: break;
}
}