This commit is contained in:
Tino Reichardt 2024-08-28 22:27:03 +02:00 committed by GitHub
commit 502eec6abf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 250 additions and 1986 deletions

View File

@ -43,8 +43,6 @@ dist_noinst_DATA += README.md RELEASES.md
dist_noinst_DATA += module/lua/README.zfs module/os/linux/spl/README.md dist_noinst_DATA += module/lua/README.zfs module/os/linux/spl/README.md
# Include all the extra licensing information for modules # Include all the extra licensing information for modules
dist_noinst_DATA += module/icp/algs/skein/THIRDPARTYLICENSE
dist_noinst_DATA += module/icp/algs/skein/THIRDPARTYLICENSE.descrip
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip
dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl dist_noinst_DATA += module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl

View File

@ -1,30 +1,36 @@
/* /*
* Interface declarations for Skein hashing. * CDDL HEADER START
* Source code author: Doug Whiting, 2008.
* This algorithm and source code is released to the public domain.
* *
* The following compile-time switches may be defined to control some * The contents of this file are subject to the terms of the
* tradeoffs between speed, code size, error checking, and security. * Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
* *
* The "default" note explains what happens when the switch is not defined. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
* *
* SKEIN_DEBUG -- make callouts from inside Skein code * When distributing Covered Code, include this CDDL HEADER in each
* to examine/display intermediate values. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* [default: no callouts (no overhead)] * If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
* *
* SKEIN_ERR_CHECK -- how error checking is handled inside Skein * CDDL HEADER END
* code. If not defined, most error checking
* is disabled (for performance). Otherwise,
* the switch value is interpreted as:
* 0: use assert() to flag errors
* 1: return SKEIN_FAIL to flag errors
*/ */
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
#ifndef _SYS_SKEIN_H_ /*
#define _SYS_SKEIN_H_ * Implementation of the Skein 512-bit hash function, based
* on the public domain implementation by Doug Whiting.
*
* Copyright (c) 2008,2013 Doug Whiting
*/
#ifndef _SYS_SKEIN_H
#define _SYS_SKEIN_H
#ifdef _KERNEL #ifdef _KERNEL
#include <sys/types.h> /* get size_t definition */ #include <sys/types.h>
#else #else
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -34,74 +40,34 @@
extern "C" { extern "C" {
#endif #endif
enum { #define SKEIN_512_STATE_WORDS 8
SKEIN_SUCCESS = 0, /* return codes from Skein calls */
SKEIN_FAIL = 1,
SKEIN_BAD_HASHLEN = 2
};
#define SKEIN_MODIFIER_WORDS (2) /* number of modifier (tweak) words */
#define SKEIN_256_STATE_WORDS (4)
#define SKEIN_512_STATE_WORDS (8)
#define SKEIN1024_STATE_WORDS (16)
#define SKEIN_MAX_STATE_WORDS (16)
#define SKEIN_256_STATE_BYTES (8 * SKEIN_256_STATE_WORDS)
#define SKEIN_512_STATE_BYTES (8 * SKEIN_512_STATE_WORDS) #define SKEIN_512_STATE_BYTES (8 * SKEIN_512_STATE_WORDS)
#define SKEIN1024_STATE_BYTES (8 * SKEIN1024_STATE_WORDS)
#define SKEIN_256_STATE_BITS (64 * SKEIN_256_STATE_WORDS)
#define SKEIN_512_STATE_BITS (64 * SKEIN_512_STATE_WORDS)
#define SKEIN1024_STATE_BITS (64 * SKEIN1024_STATE_WORDS)
#define SKEIN_256_BLOCK_BYTES (8 * SKEIN_256_STATE_WORDS)
#define SKEIN_512_BLOCK_BYTES (8 * SKEIN_512_STATE_WORDS) #define SKEIN_512_BLOCK_BYTES (8 * SKEIN_512_STATE_WORDS)
#define SKEIN1024_BLOCK_BYTES (8 * SKEIN1024_STATE_WORDS)
typedef struct { typedef struct {
size_t hashBitLen; /* size of hash result, in bits */ size_t hashBitLen; /* size of hash result, in bits */
size_t bCnt; /* current byte count in buffer b[] */ size_t bCnt; /* current byte count in buffer b[] */
/* tweak words: T[0]=byte cnt, T[1]=flags */ uint64_t T[2]; /* tweak words: T[0]=byte cnt, T[1]=flags */
uint64_t T[SKEIN_MODIFIER_WORDS];
} Skein_Ctxt_Hdr_t; } Skein_Ctxt_Hdr_t;
typedef struct { /* 256-bit Skein hash context structure */
Skein_Ctxt_Hdr_t h; /* common header context variables */
uint64_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */
/* partial block buffer (8-byte aligned) */
uint8_t b[SKEIN_256_BLOCK_BYTES];
} Skein_256_Ctxt_t;
typedef struct { /* 512-bit Skein hash context structure */ typedef struct { /* 512-bit Skein hash context structure */
Skein_Ctxt_Hdr_t h; /* common header context variables */ Skein_Ctxt_Hdr_t h; /* common header context variables */
uint64_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ uint64_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */
/* partial block buffer (8-byte aligned) */ /* partial block buffer (8-byte aligned) */
uint8_t b[SKEIN_512_BLOCK_BYTES]; uint8_t b[SKEIN_512_BLOCK_BYTES];
} Skein_512_Ctxt_t; } SKEIN_CTX;
typedef struct { /* 1024-bit Skein hash context structure */ /* Skein APIs for (incremental) "straight hashing" */
Skein_Ctxt_Hdr_t h; /* common header context variables */ extern void Skein_512_Init(SKEIN_CTX *ctx, size_t hashBitLen);
uint64_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ extern void Skein_512_Update(SKEIN_CTX *ctx, const uint8_t *msg, size_t cnt);
/* partial block buffer (8-byte aligned) */ extern void Skein_512_Final(SKEIN_CTX *ctx, uint8_t *hashVal);
uint8_t b[SKEIN1024_BLOCK_BYTES];
} Skein1024_Ctxt_t;
/* Skein APIs for (incremental) "straight hashing" */ /*
int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen); * Skein APIs for MAC and tree hash:
int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen); * Final_Pad: pad, do final block, but no OUTPUT type
int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen); * Output: do just the output stage
*/
int Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg, extern void Skein_512_Final_Pad(SKEIN_CTX *ctx, uint8_t *hashVal);
size_t msgByteCnt);
int Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg,
size_t msgByteCnt);
int Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg,
size_t msgByteCnt);
int Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
int Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
int Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
/* /*
* Skein APIs for "extended" initialization: MAC keys, tree hashing. * Skein APIs for "extended" initialization: MAC keys, tree hashing.
@ -117,58 +83,11 @@ int Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
* to precompute the MAC IV, then a copy of the context saved and * to precompute the MAC IV, then a copy of the context saved and
* reused for each new MAC computation. * reused for each new MAC computation.
*/ */
int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, extern void Skein_512_InitExt(SKEIN_CTX *ctx, size_t hashBitLen,
uint64_t treeInfo, const uint8_t *key, size_t keyBytes); uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen,
uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen,
uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
/*
* Skein APIs for MAC and tree hash:
* Final_Pad: pad, do final block, but no OUTPUT type
* Output: do just the output stage
*/
int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
#ifndef SKEIN_TREE_HASH
#define SKEIN_TREE_HASH (1)
#endif
#if SKEIN_TREE_HASH
int Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
int Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
int Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
#endif
/*
* When you initialize a Skein KCF hashing method you can pass this param
* structure in cm_param to fine-tune the algorithm's defaults.
*/
typedef struct skein_param {
size_t sp_digest_bitlen; /* length of digest in bits */
} skein_param_t;
/* Module definitions */
#ifdef SKEIN_MODULE_IMPL
#define CKM_SKEIN_256_MAC "CKM_SKEIN_256_MAC"
#define CKM_SKEIN_512_MAC "CKM_SKEIN_512_MAC"
#define CKM_SKEIN1024_MAC "CKM_SKEIN1024_MAC"
typedef enum skein_mech_type {
SKEIN_256_MAC_MECH_INFO_TYPE,
SKEIN_512_MAC_MECH_INFO_TYPE,
SKEIN1024_MAC_MECH_INFO_TYPE
} skein_mech_type_t;
#define VALID_SKEIN_MAC_MECH(__mech) \
((int)(__mech) >= SKEIN_256_MAC_MECH_INFO_TYPE && \
(__mech) <= SKEIN1024_MAC_MECH_INFO_TYPE)
#endif /* SKEIN_MODULE_IMPL */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _SYS_SKEIN_H_ */ #endif /* _SYS_SKEIN_H */

View File

@ -27,7 +27,6 @@ nodist_libicp_la_SOURCES = \
module/icp/algs/sha2/sha512_impl.c \ module/icp/algs/sha2/sha512_impl.c \
module/icp/algs/skein/skein.c \ module/icp/algs/skein/skein.c \
module/icp/algs/skein/skein_block.c \ module/icp/algs/skein/skein_block.c \
module/icp/algs/skein/skein_iv.c \
module/icp/illumos-crypto.c \ module/icp/illumos-crypto.c \
module/icp/io/aes.c \ module/icp/io/aes.c \
module/icp/io/sha2_mod.c \ module/icp/io/sha2_mod.c \

View File

@ -110,7 +110,6 @@ ICP_OBJS := \
algs/sha2/sha512_impl.o \ algs/sha2/sha512_impl.o \
algs/skein/skein.o \ algs/skein/skein.o \
algs/skein/skein_block.o \ algs/skein/skein_block.o \
algs/skein/skein_iv.o \
api/kcf_cipher.o \ api/kcf_cipher.o \
api/kcf_ctxops.o \ api/kcf_ctxops.o \
api/kcf_mac.o \ api/kcf_mac.o \

View File

@ -1,3 +0,0 @@
Implementation of the Skein hash function.
Source code author: Doug Whiting, 2008.
This algorithm and source code is released to the public domain.

View File

@ -1 +0,0 @@
LICENSE TERMS OF SKEIN HASH ALGORITHM IMPLEMENTATION

View File

@ -1,300 +1,77 @@
/* /*
* Implementation of the Skein hash function. * CDDL HEADER START
* Source code author: Doug Whiting, 2008. *
* This algorithm and source code is released to the public domain. * The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/ */
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/skein.h> /* get the Skein API definitions */
#include "skein_impl.h" /* get internal definitions */
/* 256-bit Skein */
/* init the context for a straight hashing operation */
int
Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
{
union {
uint8_t b[SKEIN_256_STATE_BYTES];
uint64_t w[SKEIN_256_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
switch (hashBitLen) { /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 256:
memcpy(ctx->X, SKEIN_256_IV_256, sizeof (ctx->X));
break;
case 224:
memcpy(ctx->X, SKEIN_256_IV_224, sizeof (ctx->X));
break;
case 160:
memcpy(ctx->X, SKEIN_256_IV_160, sizeof (ctx->X));
break;
case 128:
memcpy(ctx->X, SKEIN_256_IV_128, sizeof (ctx->X));
break;
#endif
default:
/* here if there is no precomputed IV value available */
/*
* build/process the config block, type == CONFIG (could be
* precomputed)
*/
/* set tweaks: T0=0; T1=CFG | FINAL */
Skein_Start_New_Type(ctx, CFG_FINAL);
/* set the schema, version */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
/* hash result length in bits */
cfg.w[1] = Skein_Swap64(hashBitLen);
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
/* zero pad config block */
memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));
/* compute the initial chaining values from config block */
/* zero the chaining variables */
memset(ctx->X, 0, sizeof (ctx->X));
Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
break;
}
/*
* The chaining vars ctx->X are now initialized for the given
* hashBitLen.
* Set up to process the data message portion of the hash (default)
*/
Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
return (SKEIN_SUCCESS);
}
/* init the context for a MAC and/or tree hash operation */
/* /*
* [identical to Skein_256_Init() when keyBytes == 0 && * Implementation of the Skein 512-bit hash function, based
* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] * on the public domain implementation by Doug Whiting.
*
* Copyright (c) 2008,2013 Doug Whiting
* Copyright (c) 2023 Tino Reichardt <milky-zfs@mcmilk.de>
*/ */
int
Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
const uint8_t *key, size_t keyBytes)
{
union {
uint8_t b[SKEIN_256_STATE_BYTES];
uint64_t w[SKEIN_256_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); #include <sys/zfs_context.h>
Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL); #include <sys/skein.h>
/* compute the initial chaining values ctx->X[], based on key */ #include "skein_impl.h"
if (keyBytes == 0) { /* is there a key? */
/* no key: use all zeroes as key for config block */
memset(ctx->X, 0, sizeof (ctx->X));
} else { /* here to pre-process a key */
Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
/* do a mini-Init right here */
/* set output hash bit count = state size */
ctx->h.hashBitLen = 8 * sizeof (ctx->X);
/* set tweaks: T0 = 0; T1 = KEY type */
Skein_Start_New_Type(ctx, KEY);
/* zero the initial chaining variables */
memset(ctx->X, 0, sizeof (ctx->X));
/* hash the key */
(void) Skein_256_Update(ctx, key, keyBytes);
/* put result into cfg.b[] */
(void) Skein_256_Final_Pad(ctx, cfg.b);
/* copy over into ctx->X[] */
memcpy(ctx->X, cfg.b, sizeof (cfg.b));
#if SKEIN_NEED_SWAP
{
uint_t i;
/* convert key bytes to context words */
for (i = 0; i < SKEIN_256_STATE_WORDS; i++)
ctx->X[i] = Skein_Swap64(ctx->X[i]);
}
#endif
}
/*
* build/process the config block, type == CONFIG (could be
* precomputed for each key)
*/
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx, CFG_FINAL);
memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
cfg.w[2] = Skein_Swap64(treeInfo);
Skein_Show_Key(256, &ctx->h, key, keyBytes);
/* compute the initial chaining values from config block */
Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
/* The chaining vars ctx->X are now initialized */
/* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx, MSG);
return (SKEIN_SUCCESS);
}
/* process the input bytes */
int
Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
{
size_t n;
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
/* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) {
/* finish up any buffered message data */
if (ctx->h.bCnt) {
/* # bytes free in buffer b[] */
n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;
if (n) {
/* check on our logic here */
Skein_assert(n < msgByteCnt);
memcpy(&ctx->b[ctx->h.bCnt], msg, n);
msgByteCnt -= n;
msg += n;
ctx->h.bCnt += n;
}
Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
Skein_256_Process_Block(ctx, ctx->b, 1,
SKEIN_256_BLOCK_BYTES);
ctx->h.bCnt = 0;
}
/*
* now process any remaining full blocks, directly from input
* message data
*/
if (msgByteCnt > SKEIN_256_BLOCK_BYTES) {
/* number of full blocks to process */
n = (msgByteCnt - 1) / SKEIN_256_BLOCK_BYTES;
Skein_256_Process_Block(ctx, msg, n,
SKEIN_256_BLOCK_BYTES);
msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
msg += n * SKEIN_256_BLOCK_BYTES;
}
Skein_assert(ctx->h.bCnt == 0);
}
/* copy any remaining source message data bytes into b[] */
if (msgByteCnt) {
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);
ctx->h.bCnt += msgByteCnt;
}
return (SKEIN_SUCCESS);
}
/* finalize the hash computation and output the result */
int
Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
{
size_t i, n, byteCnt;
uint64_t X[SKEIN_256_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
/* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0,
SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
/* process the final block */
Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
/* now output the result */
/* total number of output bytes */
byteCnt = (ctx->h.hashBitLen + 7) >> 3;
/* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
Skein_Start_New_Type(ctx, OUT_FINAL);
/* run "counter mode" */
Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
/* number of output bytes left to go */
n = byteCnt - i * SKEIN_256_BLOCK_BYTES;
if (n >= SKEIN_256_BLOCK_BYTES)
n = SKEIN_256_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */
Skein_Show_Final(256, &ctx->h, n,
hashVal + i * SKEIN_256_BLOCK_BYTES);
/* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X));
}
return (SKEIN_SUCCESS);
}
/* 512-bit Skein */ /* 512-bit Skein */
/* init the context for a straight hashing operation */ /* blkSize = 512 bits. hashSize = 256 bits */
int const uint64_t SKEIN_512_IV_256[] = {
Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) SKEIN_MK_64(0xCCD044A1, 0x2FDB3E13),
{ SKEIN_MK_64(0xE8359030, 0x1A79A9EB),
union { SKEIN_MK_64(0x55AEA061, 0x4F816E6F),
uint8_t b[SKEIN_512_STATE_BYTES]; SKEIN_MK_64(0x2A2767A4, 0xAE9B94DB),
uint64_t w[SKEIN_512_STATE_WORDS]; SKEIN_MK_64(0xEC06025E, 0x74DD7683),
} cfg; /* config block */ SKEIN_MK_64(0xE7A436CD, 0xC4746251),
SKEIN_MK_64(0xC36FBAF9, 0x393AD185),
SKEIN_MK_64(0x3EEDBA18, 0x33EDFC13)
};
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN); /* blkSize = 512 bits. hashSize = 512 bits */
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ const uint64_t SKEIN_512_IV_512[] = {
SKEIN_MK_64(0x4903ADFF, 0x749C51CE),
SKEIN_MK_64(0x0D95DE39, 0x9746DF03),
SKEIN_MK_64(0x8FD19341, 0x27C79BCE),
SKEIN_MK_64(0x9A255629, 0xFF352CB1),
SKEIN_MK_64(0x5DB62599, 0xDF6CA7B0),
SKEIN_MK_64(0xEABE394C, 0xA9D5C3F4),
SKEIN_MK_64(0x991112C7, 0x1A75B523),
SKEIN_MK_64(0xAE18A40B, 0x660FCC33)
};
/* init the context for a straight hashing operation */
void
Skein_512_Init(SKEIN_CTX * ctx, size_t hashBitLen)
{
/* output hash bit count */
ctx->h.hashBitLen = hashBitLen;
switch (hashBitLen) { /* use pre-computed values, where available */ switch (hashBitLen) { /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 512: case 512:
memcpy(ctx->X, SKEIN_512_IV_512, sizeof (ctx->X)); memcpy(ctx->X, SKEIN_512_IV_512, sizeof (ctx->X));
break; break;
case 384:
memcpy(ctx->X, SKEIN_512_IV_384, sizeof (ctx->X));
break;
case 256: case 256:
memcpy(ctx->X, SKEIN_512_IV_256, sizeof (ctx->X)); memcpy(ctx->X, SKEIN_512_IV_256, sizeof (ctx->X));
break; break;
case 224:
memcpy(ctx->X, SKEIN_512_IV_224, sizeof (ctx->X));
break;
#endif
default:
/*
* here if there is no precomputed IV value available
* build/process the config block, type == CONFIG (could be
* precomputed)
*/
/* set tweaks: T0=0; T1=CFG | FINAL */
Skein_Start_New_Type(ctx, CFG_FINAL);
/* set the schema, version */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
/* hash result length in bits */
cfg.w[1] = Skein_Swap64(hashBitLen);
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
/* zero pad config block */
memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));
/* compute the initial chaining values from config block */
/* zero the chaining variables */
memset(ctx->X, 0, sizeof (ctx->X));
Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
break;
} }
/* /*
@ -303,17 +80,11 @@ Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
* hash (default) * hash (default)
*/ */
Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */ Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
return (SKEIN_SUCCESS);
} }
/* init the context for a MAC and/or tree hash operation */ /* init the context for a MAC and/or tree hash operation */
/* void
* [identical to Skein_512_Init() when keyBytes == 0 && Skein_512_InitExt(SKEIN_CTX *ctx, size_t hashBitLen, uint64_t treeInfo,
* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]
*/
int
Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
const uint8_t *key, size_t keyBytes) const uint8_t *key, size_t keyBytes)
{ {
union { union {
@ -321,16 +92,11 @@ Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
uint64_t w[SKEIN_512_STATE_WORDS]; uint64_t w[SKEIN_512_STATE_WORDS];
} cfg; /* config block */ } cfg; /* config block */
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);
/* compute the initial chaining values ctx->X[], based on key */ /* compute the initial chaining values ctx->X[], based on key */
if (keyBytes == 0) { /* is there a key? */ if (keyBytes == 0) { /* is there a key? */
/* no key: use all zeroes as key for config block */ /* no key: use all zeroes as key for config block */
memset(ctx->X, 0, sizeof (ctx->X)); memset(ctx->X, 0, sizeof (ctx->X));
} else { /* here to pre-process a key */ } else { /* here to pre-process a key */
Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
/* do a mini-Init right here */ /* do a mini-Init right here */
/* set output hash bit count = state size */ /* set output hash bit count = state size */
ctx->h.hashBitLen = 8 * sizeof (ctx->X); ctx->h.hashBitLen = 8 * sizeof (ctx->X);
@ -338,9 +104,10 @@ Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
Skein_Start_New_Type(ctx, KEY); Skein_Start_New_Type(ctx, KEY);
/* zero the initial chaining variables */ /* zero the initial chaining variables */
memset(ctx->X, 0, sizeof (ctx->X)); memset(ctx->X, 0, sizeof (ctx->X));
(void) Skein_512_Update(ctx, key, keyBytes); /* hash the key */ /* hash the key */
Skein_512_Update(ctx, key, keyBytes);
/* put result into cfg.b[] */ /* put result into cfg.b[] */
(void) Skein_512_Final_Pad(ctx, cfg.b); Skein_512_Final_Pad(ctx, cfg.b);
/* copy over into ctx->X[] */ /* copy over into ctx->X[] */
memcpy(ctx->X, cfg.b, sizeof (cfg.b)); memcpy(ctx->X, cfg.b, sizeof (cfg.b));
#if SKEIN_NEED_SWAP #if SKEIN_NEED_SWAP
@ -359,14 +126,14 @@ Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx, CFG_FINAL); Skein_Start_New_Type(ctx, CFG_FINAL);
memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */ /* pre-pad cfg.w[] with zeroes */
memset(&cfg.w, 0, sizeof (cfg.w));
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */
/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
cfg.w[2] = Skein_Swap64(treeInfo); cfg.w[2] = Skein_Swap64(treeInfo);
Skein_Show_Key(512, &ctx->h, key, keyBytes);
/* compute the initial chaining values from config block */ /* compute the initial chaining values from config block */
Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN); Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
@ -374,19 +141,14 @@ Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
/* Set up to process the data message portion of the hash (default) */ /* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */ ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx, MSG); Skein_Start_New_Type(ctx, MSG);
return (SKEIN_SUCCESS);
} }
/* process the input bytes */ /* process the input bytes */
int void
Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt) Skein_512_Update(SKEIN_CTX *ctx, const uint8_t *msg, size_t msgByteCnt)
{ {
size_t n; size_t n;
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
/* process full blocks, if any */ /* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) { if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) {
/* finish up any buffered message data */ /* finish up any buffered message data */
@ -395,13 +157,11 @@ Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;
if (n) { if (n) {
/* check on our logic here */ /* check on our logic here */
Skein_assert(n < msgByteCnt);
memcpy(&ctx->b[ctx->h.bCnt], msg, n); memcpy(&ctx->b[ctx->h.bCnt], msg, n);
msgByteCnt -= n; msgByteCnt -= n;
msg += n; msg += n;
ctx->h.bCnt += n; ctx->h.bCnt += n;
} }
Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
Skein_512_Process_Block(ctx, ctx->b, 1, Skein_512_Process_Block(ctx, ctx->b, 1,
SKEIN_512_BLOCK_BYTES); SKEIN_512_BLOCK_BYTES);
ctx->h.bCnt = 0; ctx->h.bCnt = 0;
@ -418,30 +178,24 @@ Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
msg += n * SKEIN_512_BLOCK_BYTES; msg += n * SKEIN_512_BLOCK_BYTES;
} }
Skein_assert(ctx->h.bCnt == 0);
} }
/* copy any remaining source message data bytes into b[] */ /* copy any remaining source message data bytes into b[] */
if (msgByteCnt) { if (msgByteCnt) {
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt); memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);
ctx->h.bCnt += msgByteCnt; ctx->h.bCnt += msgByteCnt;
} }
return (SKEIN_SUCCESS);
} }
/* finalize the hash computation and output the result */ /* finalize the hash computation and output the result */
int void
Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal) Skein_512_Final(SKEIN_CTX *ctx, uint8_t *hashVal)
{ {
size_t i, n, byteCnt; size_t i, n, byteCnt;
uint64_t X[SKEIN_512_STATE_WORDS]; uint64_t X[SKEIN_512_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
/* zero pad b[] if necessary */ /* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0, memset(&ctx->b[ctx->h.bCnt], 0,
@ -457,8 +211,10 @@ Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
/* run Threefish in "counter mode" to generate output */ /* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */ /* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b)); memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */ /* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X)); memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) { for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */ /* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i); *(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
@ -469,434 +225,32 @@ Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
n = byteCnt - i * SKEIN_512_BLOCK_BYTES; n = byteCnt - i * SKEIN_512_BLOCK_BYTES;
if (n >= SKEIN_512_BLOCK_BYTES) if (n >= SKEIN_512_BLOCK_BYTES)
n = SKEIN_512_BLOCK_BYTES; n = SKEIN_512_BLOCK_BYTES;
/* "output" the ctr mode bytes */
Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES, Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */ ctx->X, n);
Skein_Show_Final(512, &ctx->h, n,
hashVal + i * SKEIN_512_BLOCK_BYTES);
/* restore the counter mode key for next time */ /* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X)); memcpy(ctx->X, X, sizeof (X));
} }
return (SKEIN_SUCCESS);
}
/* 1024-bit Skein */
/* init the context for a straight hashing operation */
int
Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
{
union {
uint8_t b[SKEIN1024_STATE_BYTES];
uint64_t w[SKEIN1024_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
switch (hashBitLen) { /* use pre-computed values, where available */
#ifndef SKEIN_NO_PRECOMP
case 512:
memcpy(ctx->X, SKEIN1024_IV_512, sizeof (ctx->X));
break;
case 384:
memcpy(ctx->X, SKEIN1024_IV_384, sizeof (ctx->X));
break;
case 1024:
memcpy(ctx->X, SKEIN1024_IV_1024, sizeof (ctx->X));
break;
#endif
default:
/* here if there is no precomputed IV value available */
/*
* build/process the config block, type == CONFIG (could be
* precomputed)
*/
/* set tweaks: T0=0; T1=CFG | FINAL */
Skein_Start_New_Type(ctx, CFG_FINAL);
/* set the schema, version */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
/* hash result length in bits */
cfg.w[1] = Skein_Swap64(hashBitLen);
cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
/* zero pad config block */
memset(&cfg.w[3], 0, sizeof (cfg) - 3 * sizeof (cfg.w[0]));
/* compute the initial chaining values from config block */
/* zero the chaining variables */
memset(ctx->X, 0, sizeof (ctx->X));
Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
break;
}
/*
* The chaining vars ctx->X are now initialized for the given
* hashBitLen. Set up to process the data message portion of the hash
* (default)
*/
Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
return (SKEIN_SUCCESS);
}
/* init the context for a MAC and/or tree hash operation */
/*
* [identical to Skein1024_Init() when keyBytes == 0 &&
* treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]
*/
int
Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
const uint8_t *key, size_t keyBytes)
{
union {
uint8_t b[SKEIN1024_STATE_BYTES];
uint64_t w[SKEIN1024_STATE_WORDS];
} cfg; /* config block */
Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);
/* compute the initial chaining values ctx->X[], based on key */
if (keyBytes == 0) { /* is there a key? */
/* no key: use all zeroes as key for config block */
memset(ctx->X, 0, sizeof (ctx->X));
} else { /* here to pre-process a key */
Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
/* do a mini-Init right here */
/* set output hash bit count = state size */
ctx->h.hashBitLen = 8 * sizeof (ctx->X);
/* set tweaks: T0 = 0; T1 = KEY type */
Skein_Start_New_Type(ctx, KEY);
/* zero the initial chaining variables */
memset(ctx->X, 0, sizeof (ctx->X));
(void) Skein1024_Update(ctx, key, keyBytes); /* hash the key */
/* put result into cfg.b[] */
(void) Skein1024_Final_Pad(ctx, cfg.b);
/* copy over into ctx->X[] */
memcpy(ctx->X, cfg.b, sizeof (cfg.b));
#if SKEIN_NEED_SWAP
{
uint_t i;
/* convert key bytes to context words */
for (i = 0; i < SKEIN1024_STATE_WORDS; i++)
ctx->X[i] = Skein_Swap64(ctx->X[i]);
}
#endif
}
/*
* build/process the config block, type == CONFIG (could be
* precomputed for each key)
*/
ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
Skein_Start_New_Type(ctx, CFG_FINAL);
memset(&cfg.w, 0, sizeof (cfg.w)); /* pre-pad cfg.w[] with zeroes */
cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
/* hash result length in bits */
cfg.w[1] = Skein_Swap64(hashBitLen);
/* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
cfg.w[2] = Skein_Swap64(treeInfo);
Skein_Show_Key(1024, &ctx->h, key, keyBytes);
/* compute the initial chaining values from config block */
Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
/* The chaining vars ctx->X are now initialized */
/* Set up to process the data message portion of the hash (default) */
ctx->h.bCnt = 0; /* buffer b[] starts out empty */
Skein_Start_New_Type(ctx, MSG);
return (SKEIN_SUCCESS);
}
/* process the input bytes */
int
Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
{
size_t n;
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
/* process full blocks, if any */
if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) {
/* finish up any buffered message data */
if (ctx->h.bCnt) {
/* # bytes free in buffer b[] */
n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;
if (n) {
/* check on our logic here */
Skein_assert(n < msgByteCnt);
memcpy(&ctx->b[ctx->h.bCnt], msg, n);
msgByteCnt -= n;
msg += n;
ctx->h.bCnt += n;
}
Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
Skein1024_Process_Block(ctx, ctx->b, 1,
SKEIN1024_BLOCK_BYTES);
ctx->h.bCnt = 0;
}
/*
* now process any remaining full blocks, directly from
* input message data
*/
if (msgByteCnt > SKEIN1024_BLOCK_BYTES) {
/* number of full blocks to process */
n = (msgByteCnt - 1) / SKEIN1024_BLOCK_BYTES;
Skein1024_Process_Block(ctx, msg, n,
SKEIN1024_BLOCK_BYTES);
msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
msg += n * SKEIN1024_BLOCK_BYTES;
}
Skein_assert(ctx->h.bCnt == 0);
}
/* copy any remaining source message data bytes into b[] */
if (msgByteCnt) {
Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
memcpy(&ctx->b[ctx->h.bCnt], msg, msgByteCnt);
ctx->h.bCnt += msgByteCnt;
}
return (SKEIN_SUCCESS);
}
/* finalize the hash computation and output the result */
int
Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
{
size_t i, n, byteCnt;
uint64_t X[SKEIN1024_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
/* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0,
SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
/* process the final block */
Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
/* now output the result */
/* total number of output bytes */
byteCnt = (ctx->h.hashBitLen + 7) >> 3;
/* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
Skein_Start_New_Type(ctx, OUT_FINAL);
/* run "counter mode" */
Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
/* number of output bytes left to go */
n = byteCnt - i * SKEIN1024_BLOCK_BYTES;
if (n >= SKEIN1024_BLOCK_BYTES)
n = SKEIN1024_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */
Skein_Show_Final(1024, &ctx->h, n,
hashVal + i * SKEIN1024_BLOCK_BYTES);
/* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X));
}
return (SKEIN_SUCCESS);
}
/* Functions to support MAC/tree hashing */
/* (this code is identical for Optimized and Reference versions) */
/* finalize the hash computation and output the block, no OUTPUT stage */
int
Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
{
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
/* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0,
SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
/* process the final block */
Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
/* "output" the state bytes */
Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_256_BLOCK_BYTES);
return (SKEIN_SUCCESS);
} }
/* finalize the hash computation and output the block, no OUTPUT stage */ /* finalize the hash computation and output the block, no OUTPUT stage */
int void
Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal) Skein_512_Final_Pad(SKEIN_CTX *ctx, uint8_t *hashVal)
{ {
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */
/* zero pad b[] if necessary */ /* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0, memset(&ctx->b[ctx->h.bCnt], 0,
SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
/* process the final block */ /* process the final block */
Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt); Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
/* "output" the state bytes */ /* "output" the state bytes */
Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_512_BLOCK_BYTES); Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_512_BLOCK_BYTES);
return (SKEIN_SUCCESS);
} }
/* finalize the hash computation and output the block, no OUTPUT stage */
int
Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
{
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
/* tag as the final block */
ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;
/* zero pad b[] if necessary */
if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)
memset(&ctx->b[ctx->h.bCnt], 0,
SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
/* process the final block */
Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
/* "output" the state bytes */
Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN1024_BLOCK_BYTES);
return (SKEIN_SUCCESS);
}
#if SKEIN_TREE_HASH
/* just do the OUTPUT stage */
int
Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
{
size_t i, n, byteCnt;
uint64_t X[SKEIN_256_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
/* now output the result */
/* total number of output bytes */
byteCnt = (ctx->h.hashBitLen + 7) >> 3;
/* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
Skein_Start_New_Type(ctx, OUT_FINAL);
/* run "counter mode" */
Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
/* number of output bytes left to go */
n = byteCnt - i * SKEIN_256_BLOCK_BYTES;
if (n >= SKEIN_256_BLOCK_BYTES)
n = SKEIN_256_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */
Skein_Show_Final(256, &ctx->h, n,
hashVal + i * SKEIN_256_BLOCK_BYTES);
/* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X));
}
return (SKEIN_SUCCESS);
}
/* just do the OUTPUT stage */
int
Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
{
size_t i, n, byteCnt;
uint64_t X[SKEIN_512_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
/* now output the result */
/* total number of output bytes */
byteCnt = (ctx->h.hashBitLen + 7) >> 3;
/* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
Skein_Start_New_Type(ctx, OUT_FINAL);
/* run "counter mode" */
Skein_512_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
/* number of output bytes left to go */
n = byteCnt - i * SKEIN_512_BLOCK_BYTES;
if (n >= SKEIN_512_BLOCK_BYTES)
n = SKEIN_512_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */
Skein_Show_Final(256, &ctx->h, n,
hashVal + i * SKEIN_512_BLOCK_BYTES);
/* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X));
}
return (SKEIN_SUCCESS);
}
/* just do the OUTPUT stage */
int
Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
{
size_t i, n, byteCnt;
uint64_t X[SKEIN1024_STATE_WORDS];
/* catch uninitialized context */
Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
/* now output the result */
/* total number of output bytes */
byteCnt = (ctx->h.hashBitLen + 7) >> 3;
/* run Threefish in "counter mode" to generate output */
/* zero out b[], so it can hold the counter */
memset(ctx->b, 0, sizeof (ctx->b));
/* keep a local copy of counter mode "key" */
memcpy(X, ctx->X, sizeof (X));
for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {
/* build the counter block */
*(uint64_t *)ctx->b = Skein_Swap64((uint64_t)i);
Skein_Start_New_Type(ctx, OUT_FINAL);
/* run "counter mode" */
Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
/* number of output bytes left to go */
n = byteCnt - i * SKEIN1024_BLOCK_BYTES;
if (n >= SKEIN1024_BLOCK_BYTES)
n = SKEIN1024_BLOCK_BYTES;
Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,
ctx->X, n); /* "output" the ctr mode bytes */
Skein_Show_Final(256, &ctx->h, n,
hashVal + i * SKEIN1024_BLOCK_BYTES);
/* restore the counter mode key for next time */
memcpy(ctx->X, X, sizeof (X));
}
return (SKEIN_SUCCESS);
}
#endif
#ifdef _KERNEL #ifdef _KERNEL
EXPORT_SYMBOL(Skein_512_Init); EXPORT_SYMBOL(Skein_512_Init);
EXPORT_SYMBOL(Skein_512_InitExt); EXPORT_SYMBOL(Skein_512_InitExt);

View File

@ -1,49 +1,54 @@
/* /*
* Implementation of the Skein block functions. * CDDL HEADER START
* Source code author: Doug Whiting, 2008. *
* This algorithm and source code is released to the public domain. * The contents of this file are subject to the terms of the
* Compile-time switches: * Common Development and Distribution License (the "License").
* SKEIN_USE_ASM -- set bits (256/512/1024) to select which * You may not use this file except in compliance with the License.
* versions use ASM code for block processing *
* [default: use C for all block sizes] * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/ */
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
/*
* Implementation of the Skein 512-bit hash function, based
* on the public domain implementation by Doug Whiting.
*
* Copyright (c) 2008,2013 Doug Whiting
* Copyright (c) 2023 Tino Reichardt <milky-zfs@mcmilk.de>
*/
#include <sys/zfs_context.h>
#include <sys/skein.h> #include <sys/skein.h>
#include "skein_impl.h"
#include <sys/isa_defs.h> /* for _ILP32 */
#ifndef SKEIN_USE_ASM #include "skein_impl.h"
#define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */
#endif #define rotl64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
#ifndef SKEIN_LOOP #ifndef SKEIN_LOOP
#if defined(_ILP32) || defined(__powerpc) /* Assume small stack */
/* /*
* The low-level checksum routines use a lot of stack space. On systems where * The low-level checksum routines use a lot of stack space. On systems where
* small stacks frame are enforced (like 32-bit kernel builds), do not unroll * small stacks frame are enforced (like 32-bit kernel builds), do not unroll
* checksum calculations to save stack space. * checksum calculations to save stack space.
* *
* Even with no loops unrolled, we still can exceed the 1k stack frame limit
* in Skein1024_Process_Block() (it hits 1272 bytes on ARM32). We can
* safely ignore it though, since that the checksum functions will be called
* from a worker thread that won't be using much stack. That's why we have
* the #pragma here to ignore the warning.
*/
#if defined(_ILP32) || defined(__powerpc) /* Assume small stack */
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic ignored "-Wframe-larger-than="
#endif
/*
* We're running on 32-bit, don't unroll loops to save stack frame space
*
* Due to the ways the calculations on SKEIN_LOOP are done in * Due to the ways the calculations on SKEIN_LOOP are done in
* Skein_*_Process_Block(), a value of 111 disables unrolling loops * Skein_*_Process_Block(), a value of 111 disables unrolling loops
* in any of those functions. * in any of those functions.
*/ */
#define SKEIN_LOOP 111 #define SKEIN_LOOP 111
#else #else
/* We're compiling with large stacks */ /* We're compiling with large stacks, so with unroll */
#define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ #define SKEIN_LOOP 001
#endif #endif
#endif #endif
@ -54,217 +59,9 @@
#define ks (kw + KW_KEY_BASE) #define ks (kw + KW_KEY_BASE)
#define ts (kw + KW_TWK_BASE) #define ts (kw + KW_TWK_BASE)
/* no debugging in Illumos version */
#define DebugSaveTweak(ctx)
/* Skein_256 */
#if !(SKEIN_USE_ASM & 256)
void
Skein_256_Process_Block(Skein_256_Ctxt_t *ctx, const uint8_t *blkPtr,
size_t blkCnt, size_t byteCntAdd)
{
enum {
WCNT = SKEIN_256_STATE_WORDS
};
#undef RCNT
#define RCNT (SKEIN_256_ROUNDS_TOTAL / 8)
#ifdef SKEIN_LOOP /* configure how much to unroll the loop */
#define SKEIN_UNROLL_256 (((SKEIN_LOOP) / 100) % 10)
#else
#define SKEIN_UNROLL_256 (0)
#endif
#if SKEIN_UNROLL_256
#if (RCNT % SKEIN_UNROLL_256)
#error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */
#endif
size_t r;
/* key schedule words : chaining vars + tweak + "rotation" */
uint64_t kw[WCNT + 4 + RCNT * 2];
#else
uint64_t kw[WCNT + 4]; /* key schedule words : chaining vars + tweak */
#endif
/* local copy of context vars, for speed */
uint64_t X0, X1, X2, X3;
uint64_t w[WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
/* use for debugging (help compiler put Xn in registers) */
const uint64_t *Xptr[4];
Xptr[0] = &X0;
Xptr[1] = &X1;
Xptr[2] = &X2;
Xptr[3] = &X3;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1];
do {
/*
* this implementation only supports 2**64 input bytes
* (no carry out here)
*/
ts[0] += byteCntAdd; /* update processed length */
/* precompute the key schedule for this block */
ks[0] = ctx->X[0];
ks[1] = ctx->X[1];
ks[2] = ctx->X[2];
ks[3] = ctx->X[3];
ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY;
ts[2] = ts[0] ^ ts[1];
/* get input block in little-endian format */
Skein_Get64_LSB_First(w, blkPtr, WCNT);
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
X0 = w[0] + ks[0]; /* do the first full key injection */
X1 = w[1] + ks[1] + ts[0];
X2 = w[2] + ks[2] + ts[1];
X3 = w[3] + ks[3];
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
Xptr); /* show starting state values */
blkPtr += SKEIN_256_BLOCK_BYTES;
/* run the rounds */
#define Round256(p0, p1, p2, p3, ROT, rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0; \
X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2; \
#if SKEIN_UNROLL_256 == 0
#define R256(p0, p1, p2, p3, ROT, rNum) /* fully unrolled */ \
Round256(p0, p1, p2, p3, ROT, rNum) \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr);
#define I256(R) \
X0 += ks[((R) + 1) % 5]; /* inject the key schedule value */ \
X1 += ks[((R) + 2) % 5] + ts[((R) + 1) % 3]; \
X2 += ks[((R) + 3) % 5] + ts[((R) + 2) % 3]; \
X3 += ks[((R) + 4) % 5] + (R) + 1; \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
#else /* looping version */
#define R256(p0, p1, p2, p3, ROT, rNum) \
Round256(p0, p1, p2, p3, ROT, rNum) \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr);
#define I256(R) \
X0 += ks[r + (R) + 0]; /* inject the key schedule value */ \
X1 += ks[r + (R) + 1] + ts[r + (R) + 0]; \
X2 += ks[r + (R) + 2] + ts[r + (R) + 1]; \
X3 += ks[r + (R) + 3] + r + (R); \
ks[r + (R) + 4] = ks[r + (R) - 1]; /* rotate key schedule */ \
ts[r + (R) + 2] = ts[r + (R) - 1]; \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
/* loop through it */
for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_256)
#endif
{
#define R256_8_rounds(R) \
R256(0, 1, 2, 3, R_256_0, 8 * (R) + 1); \
R256(0, 3, 2, 1, R_256_1, 8 * (R) + 2); \
R256(0, 1, 2, 3, R_256_2, 8 * (R) + 3); \
R256(0, 3, 2, 1, R_256_3, 8 * (R) + 4); \
I256(2 * (R)); \
R256(0, 1, 2, 3, R_256_4, 8 * (R) + 5); \
R256(0, 3, 2, 1, R_256_5, 8 * (R) + 6); \
R256(0, 1, 2, 3, R_256_6, 8 * (R) + 7); \
R256(0, 3, 2, 1, R_256_7, 8 * (R) + 8); \
I256(2 * (R) + 1);
R256_8_rounds(0);
#define R256_Unroll_R(NN) \
((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL / 8 > (NN)) || \
(SKEIN_UNROLL_256 > (NN)))
#if R256_Unroll_R(1)
R256_8_rounds(1);
#endif
#if R256_Unroll_R(2)
R256_8_rounds(2);
#endif
#if R256_Unroll_R(3)
R256_8_rounds(3);
#endif
#if R256_Unroll_R(4)
R256_8_rounds(4);
#endif
#if R256_Unroll_R(5)
R256_8_rounds(5);
#endif
#if R256_Unroll_R(6)
R256_8_rounds(6);
#endif
#if R256_Unroll_R(7)
R256_8_rounds(7);
#endif
#if R256_Unroll_R(8)
R256_8_rounds(8);
#endif
#if R256_Unroll_R(9)
R256_8_rounds(9);
#endif
#if R256_Unroll_R(10)
R256_8_rounds(10);
#endif
#if R256_Unroll_R(11)
R256_8_rounds(11);
#endif
#if R256_Unroll_R(12)
R256_8_rounds(12);
#endif
#if R256_Unroll_R(13)
R256_8_rounds(13);
#endif
#if R256_Unroll_R(14)
R256_8_rounds(14);
#endif
#if (SKEIN_UNROLL_256 > 14)
#error "need more unrolling in Skein_256_Process_Block"
#endif
}
/*
* do the final "feedforward" xor, update context chaining vars
*/
ctx->X[0] = X0 ^ w[0];
ctx->X[1] = X1 ^ w[1];
ctx->X[2] = X2 ^ w[2];
ctx->X[3] = X3 ^ w[3];
Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST;
} while (--blkCnt);
ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1];
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
size_t
Skein_256_Process_Block_CodeSize(void)
{
return ((uint8_t *)Skein_256_Process_Block_CodeSize) -
((uint8_t *)Skein_256_Process_Block);
}
uint_t
Skein_256_Unroll_Cnt(void)
{
return (SKEIN_UNROLL_256);
}
#endif
#endif
/* Skein_512 */ /* Skein_512 */
#if !(SKEIN_USE_ASM & 512)
void void
Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr, Skein_512_Process_Block(SKEIN_CTX *ctx, const uint8_t *blkPtr,
size_t blkCnt, size_t byteCntAdd) size_t blkCnt, size_t byteCntAdd)
{ {
enum { enum {
@ -291,21 +88,7 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
#endif #endif
/* local copy of vars, for speed */ /* local copy of vars, for speed */
uint64_t X0, X1, X2, X3, X4, X5, X6, X7; uint64_t X0, X1, X2, X3, X4, X5, X6, X7;
uint64_t w[WCNT]; /* local copy of input block */ uint64_t w[WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
/* use for debugging (help compiler put Xn in registers) */
const uint64_t *Xptr[8];
Xptr[0] = &X0;
Xptr[1] = &X1;
Xptr[2] = &X2;
Xptr[3] = &X3;
Xptr[4] = &X4;
Xptr[5] = &X5;
Xptr[6] = &X6;
Xptr[7] = &X7;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0]; ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1]; ts[1] = ctx->h.T[1];
do { do {
@ -331,8 +114,6 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
/* get input block in little-endian format */ /* get input block in little-endian format */
Skein_Get64_LSB_First(w, blkPtr, WCNT); Skein_Get64_LSB_First(w, blkPtr, WCNT);
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
X0 = w[0] + ks[0]; /* do the first full key injection */ X0 = w[0] + ks[0]; /* do the first full key injection */
X1 = w[1] + ks[1]; X1 = w[1] + ks[1];
@ -345,19 +126,16 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
blkPtr += SKEIN_512_BLOCK_BYTES; blkPtr += SKEIN_512_BLOCK_BYTES;
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
Xptr);
/* run the rounds */ /* run the rounds */
#define Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ #define Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0;\ X##p0 += X##p1; X##p1 = rotl64(X##p1, ROT##_0); X##p1 ^= X##p0;\
X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2;\ X##p2 += X##p3; X##p3 = rotl64(X##p3, ROT##_1); X##p3 ^= X##p2;\
X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4;\ X##p4 += X##p5; X##p5 = rotl64(X##p5, ROT##_2); X##p5 ^= X##p4;\
X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6; X##p6 += X##p7; X##p7 = rotl64(X##p7, ROT##_3); X##p7 ^= X##p6;
#if SKEIN_UNROLL_512 == 0 #if SKEIN_UNROLL_512 == 0
#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) /* unrolled */ \ #define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) /* unrolled */ \
Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr);
#define I512(R) \ #define I512(R) \
X0 += ks[((R) + 1) % 9]; /* inject the key schedule value */\ X0 += ks[((R) + 1) % 9]; /* inject the key schedule value */\
@ -367,12 +145,10 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
X4 += ks[((R) + 5) % 9]; \ X4 += ks[((R) + 5) % 9]; \
X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3]; \ X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3]; \
X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3]; \ X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3]; \
X7 += ks[((R) + 8) % 9] + (R) + 1; \ X7 += ks[((R) + 8) % 9] + (R) + 1;
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
#else /* looping version */ #else /* looping version */
#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ #define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \
Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) \ Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr);
#define I512(R) \ #define I512(R) \
X0 += ks[r + (R) + 0]; /* inject the key schedule value */ \ X0 += ks[r + (R) + 0]; /* inject the key schedule value */ \
@ -384,8 +160,7 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
X6 += ks[r + (R) + 6] + ts[r + (R) + 1]; \ X6 += ks[r + (R) + 6] + ts[r + (R) + 1]; \
X7 += ks[r + (R) + 7] + r + (R); \ X7 += ks[r + (R) + 7] + r + (R); \
ks[r + (R)+8] = ks[r + (R) - 1]; /* rotate key schedule */\ ks[r + (R)+8] = ks[r + (R) - 1]; /* rotate key schedule */\
ts[r + (R)+2] = ts[r + (R) - 1]; \ ts[r + (R)+2] = ts[r + (R) - 1];
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
/* loop through it */ /* loop through it */
for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_512) for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_512)
@ -401,9 +176,9 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6); \ R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6); \
R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7); \ R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7); \
R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8); \ R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8); \
I512(2*(R) + 1); /* and key injection */ I512(2*(R) + 1); /* and key injection */
R512_8_rounds(0); R512_8_rounds(0);
#define R512_Unroll_R(NN) \ #define R512_Unroll_R(NN) \
((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL / 8 > (NN)) || \ ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL / 8 > (NN)) || \
@ -467,326 +242,10 @@ Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
ctx->X[5] = X5 ^ w[5]; ctx->X[5] = X5 ^ w[5];
ctx->X[6] = X6 ^ w[6]; ctx->X[6] = X6 ^ w[6];
ctx->X[7] = X7 ^ w[7]; ctx->X[7] = X7 ^ w[7];
Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST; ts[1] &= ~SKEIN_T1_FLAG_FIRST;
} while (--blkCnt); } while (--blkCnt);
ctx->h.T[0] = ts[0]; ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1]; ctx->h.T[1] = ts[1];
} }
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
size_t
Skein_512_Process_Block_CodeSize(void)
{
return ((uint8_t *)Skein_512_Process_Block_CodeSize) -
((uint8_t *)Skein_512_Process_Block);
}
uint_t
Skein_512_Unroll_Cnt(void)
{
return (SKEIN_UNROLL_512);
}
#endif
#endif
/* Skein1024 */
#if !(SKEIN_USE_ASM & 1024)
void
Skein1024_Process_Block(Skein1024_Ctxt_t *ctx, const uint8_t *blkPtr,
size_t blkCnt, size_t byteCntAdd)
{
/* do it in C, always looping (unrolled is bigger AND slower!) */
enum {
WCNT = SKEIN1024_STATE_WORDS
};
#undef RCNT
#define RCNT (SKEIN1024_ROUNDS_TOTAL/8)
#ifdef SKEIN_LOOP /* configure how much to unroll the loop */
#define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10)
#else
#define SKEIN_UNROLL_1024 (0)
#endif
#if (SKEIN_UNROLL_1024 != 0)
#if (RCNT % SKEIN_UNROLL_1024)
#error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */
#endif
size_t r;
/* key schedule words : chaining vars + tweak + "rotation" */
uint64_t kw[WCNT + 4 + RCNT * 2];
#else
uint64_t kw[WCNT + 4]; /* key schedule words : chaining vars + tweak */
#endif
/* local copy of vars, for speed */
uint64_t X00, X01, X02, X03, X04, X05, X06, X07, X08, X09, X10, X11,
X12, X13, X14, X15;
uint64_t w[WCNT]; /* local copy of input block */
#ifdef SKEIN_DEBUG
/* use for debugging (help compiler put Xn in registers) */
const uint64_t *Xptr[16];
Xptr[0] = &X00;
Xptr[1] = &X01;
Xptr[2] = &X02;
Xptr[3] = &X03;
Xptr[4] = &X04;
Xptr[5] = &X05;
Xptr[6] = &X06;
Xptr[7] = &X07;
Xptr[8] = &X08;
Xptr[9] = &X09;
Xptr[10] = &X10;
Xptr[11] = &X11;
Xptr[12] = &X12;
Xptr[13] = &X13;
Xptr[14] = &X14;
Xptr[15] = &X15;
#endif
Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */
ts[0] = ctx->h.T[0];
ts[1] = ctx->h.T[1];
do {
/*
* this implementation only supports 2**64 input bytes
* (no carry out here)
*/
ts[0] += byteCntAdd; /* update processed length */
/* precompute the key schedule for this block */
ks[0] = ctx->X[0];
ks[1] = ctx->X[1];
ks[2] = ctx->X[2];
ks[3] = ctx->X[3];
ks[4] = ctx->X[4];
ks[5] = ctx->X[5];
ks[6] = ctx->X[6];
ks[7] = ctx->X[7];
ks[8] = ctx->X[8];
ks[9] = ctx->X[9];
ks[10] = ctx->X[10];
ks[11] = ctx->X[11];
ks[12] = ctx->X[12];
ks[13] = ctx->X[13];
ks[14] = ctx->X[14];
ks[15] = ctx->X[15];
ks[16] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^
ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^
ks[8] ^ ks[9] ^ ks[10] ^ ks[11] ^
ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY;
ts[2] = ts[0] ^ ts[1];
/* get input block in little-endian format */
Skein_Get64_LSB_First(w, blkPtr, WCNT);
DebugSaveTweak(ctx);
Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
X00 = w[0] + ks[0]; /* do the first full key injection */
X01 = w[1] + ks[1];
X02 = w[2] + ks[2];
X03 = w[3] + ks[3];
X04 = w[4] + ks[4];
X05 = w[5] + ks[5];
X06 = w[6] + ks[6];
X07 = w[7] + ks[7];
X08 = w[8] + ks[8];
X09 = w[9] + ks[9];
X10 = w[10] + ks[10];
X11 = w[11] + ks[11];
X12 = w[12] + ks[12];
X13 = w[13] + ks[13] + ts[0];
X14 = w[14] + ks[14] + ts[1];
X15 = w[15] + ks[15];
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
Xptr);
#define Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, \
pD, pE, pF, ROT, rNum) \
X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0;\
X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2;\
X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4;\
X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6;\
X##p8 += X##p9; X##p9 = RotL_64(X##p9, ROT##_4); X##p9 ^= X##p8;\
X##pA += X##pB; X##pB = RotL_64(X##pB, ROT##_5); X##pB ^= X##pA;\
X##pC += X##pD; X##pD = RotL_64(X##pD, ROT##_6); X##pD ^= X##pC;\
X##pE += X##pF; X##pF = RotL_64(X##pF, ROT##_7); X##pF ^= X##pE;
#if SKEIN_UNROLL_1024 == 0
#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, \
pE, pF, ROT, rn) \
Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, \
pD, pE, pF, ROT, rn) \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rn, Xptr);
#define I1024(R) \
X00 += ks[((R) + 1) % 17]; /* inject the key schedule value */\
X01 += ks[((R) + 2) % 17]; \
X02 += ks[((R) + 3) % 17]; \
X03 += ks[((R) + 4) % 17]; \
X04 += ks[((R) + 5) % 17]; \
X05 += ks[((R) + 6) % 17]; \
X06 += ks[((R) + 7) % 17]; \
X07 += ks[((R) + 8) % 17]; \
X08 += ks[((R) + 9) % 17]; \
X09 += ks[((R) + 10) % 17]; \
X10 += ks[((R) + 11) % 17]; \
X11 += ks[((R) + 12) % 17]; \
X12 += ks[((R) + 13) % 17]; \
X13 += ks[((R) + 14) % 17] + ts[((R) + 1) % 3]; \
X14 += ks[((R) + 15) % 17] + ts[((R) + 2) % 3]; \
X15 += ks[((R) + 16) % 17] + (R) +1; \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
#else /* looping version */
#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, \
pE, pF, ROT, rn) \
Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, \
pD, pE, pF, ROT, rn) \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rn, Xptr);
#define I1024(R) \
X00 += ks[r + (R) + 0]; /* inject the key schedule value */ \
X01 += ks[r + (R) + 1]; \
X02 += ks[r + (R) + 2]; \
X03 += ks[r + (R) + 3]; \
X04 += ks[r + (R) + 4]; \
X05 += ks[r + (R) + 5]; \
X06 += ks[r + (R) + 6]; \
X07 += ks[r + (R) + 7]; \
X08 += ks[r + (R) + 8]; \
X09 += ks[r + (R) + 9]; \
X10 += ks[r + (R) + 10]; \
X11 += ks[r + (R) + 11]; \
X12 += ks[r + (R) + 12]; \
X13 += ks[r + (R) + 13] + ts[r + (R) + 0]; \
X14 += ks[r + (R) + 14] + ts[r + (R) + 1]; \
X15 += ks[r + (R) + 15] + r + (R); \
ks[r + (R) + 16] = ks[r + (R) - 1]; /* rotate key schedule */\
ts[r + (R) + 2] = ts[r + (R) - 1]; \
Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
/* loop through it */
for (r = 1; r <= 2 * RCNT; r += 2 * SKEIN_UNROLL_1024)
#endif
{
#define R1024_8_rounds(R) /* do 8 full rounds */ \
R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, \
14, 15, R1024_0, 8 * (R) + 1); \
R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05, \
08, 01, R1024_1, 8 * (R) + 2); \
R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11, \
10, 09, R1024_2, 8 * (R) + 3); \
R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03, \
12, 07, R1024_3, 8 * (R) + 4); \
I1024(2 * (R)); \
R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, \
14, 15, R1024_4, 8 * (R) + 5); \
R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05, \
08, 01, R1024_5, 8 * (R) + 6); \
R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11, \
10, 09, R1024_6, 8 * (R) + 7); \
R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03, \
12, 07, R1024_7, 8 * (R) + 8); \
I1024(2 * (R) + 1);
R1024_8_rounds(0);
#define R1024_Unroll_R(NN) \
((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || \
(SKEIN_UNROLL_1024 > (NN)))
#if R1024_Unroll_R(1)
R1024_8_rounds(1);
#endif
#if R1024_Unroll_R(2)
R1024_8_rounds(2);
#endif
#if R1024_Unroll_R(3)
R1024_8_rounds(3);
#endif
#if R1024_Unroll_R(4)
R1024_8_rounds(4);
#endif
#if R1024_Unroll_R(5)
R1024_8_rounds(5);
#endif
#if R1024_Unroll_R(6)
R1024_8_rounds(6);
#endif
#if R1024_Unroll_R(7)
R1024_8_rounds(7);
#endif
#if R1024_Unroll_R(8)
R1024_8_rounds(8);
#endif
#if R1024_Unroll_R(9)
R1024_8_rounds(9);
#endif
#if R1024_Unroll_R(10)
R1024_8_rounds(10);
#endif
#if R1024_Unroll_R(11)
R1024_8_rounds(11);
#endif
#if R1024_Unroll_R(12)
R1024_8_rounds(12);
#endif
#if R1024_Unroll_R(13)
R1024_8_rounds(13);
#endif
#if R1024_Unroll_R(14)
R1024_8_rounds(14);
#endif
#if (SKEIN_UNROLL_1024 > 14)
#error "need more unrolling in Skein_1024_Process_Block"
#endif
}
/*
* do the final "feedforward" xor, update context chaining vars
*/
ctx->X[0] = X00 ^ w[0];
ctx->X[1] = X01 ^ w[1];
ctx->X[2] = X02 ^ w[2];
ctx->X[3] = X03 ^ w[3];
ctx->X[4] = X04 ^ w[4];
ctx->X[5] = X05 ^ w[5];
ctx->X[6] = X06 ^ w[6];
ctx->X[7] = X07 ^ w[7];
ctx->X[8] = X08 ^ w[8];
ctx->X[9] = X09 ^ w[9];
ctx->X[10] = X10 ^ w[10];
ctx->X[11] = X11 ^ w[11];
ctx->X[12] = X12 ^ w[12];
ctx->X[13] = X13 ^ w[13];
ctx->X[14] = X14 ^ w[14];
ctx->X[15] = X15 ^ w[15];
Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
ts[1] &= ~SKEIN_T1_FLAG_FIRST;
blkPtr += SKEIN1024_BLOCK_BYTES;
} while (--blkCnt);
ctx->h.T[0] = ts[0];
ctx->h.T[1] = ts[1];
}
#if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
size_t
Skein1024_Process_Block_CodeSize(void)
{
return ((uint8_t *)Skein1024_Process_Block_CodeSize) -
((uint8_t *)Skein1024_Process_Block);
}
uint_t
Skein1024_Unroll_Cnt(void)
{
return (SKEIN_UNROLL_1024);
}
#endif
#endif

View File

@ -1,41 +1,78 @@
/* /*
* Internal definitions for Skein hashing. * CDDL HEADER START
* Source code author: Doug Whiting, 2008.
* This algorithm and source code is released to the public domain.
* *
* The following compile-time switches may be defined to control some * The contents of this file are subject to the terms of the
* tradeoffs between speed, code size, error checking, and security. * Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
* *
* The "default" note explains what happens when the switch is not defined. * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
* *
* SKEIN_DEBUG -- make callouts from inside Skein code * When distributing Covered Code, include this CDDL HEADER in each
* to examine/display intermediate values. * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* [default: no callouts (no overhead)] * If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
* *
* SKEIN_ERR_CHECK -- how error checking is handled inside Skein * CDDL HEADER END
* code. If not defined, most error checking */
* is disabled (for performance). Otherwise,
* the switch value is interpreted as: /*
* 0: use assert() to flag errors * Implementation of the Skein 512-bit hash function, based
* 1: return SKEIN_FAIL to flag errors * on the public domain implementation by Doug Whiting.
*
* Copyright (c) 2008,2013 Doug Whiting
* Copyright (c) 2023 Tino Reichardt <milky-zfs@mcmilk.de>
*/ */
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
#ifndef _SKEIN_IMPL_H_ #ifndef _SKEIN_IMPL_H_
#define _SKEIN_IMPL_H_ #define _SKEIN_IMPL_H_
#include <sys/skein.h>
#include <sys/string.h> #include <sys/string.h>
#include "skein_impl.h" #include <sys/skein.h>
#include "skein_port.h"
/* #include "skein_impl.h"
* "Internal" Skein definitions
* -- not needed for sequential hashing API, but will be #if defined(_ZFS_BIG_ENDIAN)
* helpful for other uses of Skein (e.g., tree hash mode). #define SKEIN_NEED_SWAP (1)
* -- included here so that they can be shared between #define Skein_Swap64(w64) (__builtin_bswap64(w64))
* reference and optimized code. #else
*/ #define SKEIN_NEED_SWAP (0)
#define Skein_Swap64(w64) (w64)
#define Skein_Put64_LSB_First(dst, src, bCnt) memcpy(dst, src, bCnt)
#define Skein_Get64_LSB_First(dst, src, wCnt) memcpy(dst, src, 8 * (wCnt))
#endif
#ifndef Skein_Put64_LSB_First
/* this is fully portable for all endian, but slow */
static inline void
Skein_Put64_LSB_First(uint8_t *dst, const uint64_t *src, size_t bCnt)
{
size_t n;
for (n = 0; n < bCnt; n++)
dst[n] = (uint8_t)(src[n >> 3] >> (8 * (n & 7)));
}
#endif /* ifndef Skein_Put64_LSB_First */
#ifndef Skein_Get64_LSB_First
/* this is fully portable for all endian, but slow */
static inline void
Skein_Get64_LSB_First(uint64_t *dst, const uint8_t *src, size_t wCnt)
{
size_t n;
for (n = 0; n < 8 * wCnt; n += 8)
dst[n / 8] = (((uint64_t)src[n])) +
(((uint64_t)src[n + 1]) << 8) +
(((uint64_t)src[n + 2]) << 16) +
(((uint64_t)src[n + 3]) << 24) +
(((uint64_t)src[n + 4]) << 32) +
(((uint64_t)src[n + 5]) << 40) +
(((uint64_t)src[n + 6]) << 48) +
(((uint64_t)src[n + 7]) << 56);
}
#endif /* ifndef Skein_Get64_LSB_First */
/* tweak word T[1]: bit field starting positions */ /* tweak word T[1]: bit field starting positions */
/* offset 64 because it's the second word */ /* offset 64 because it's the second word */
@ -65,7 +102,7 @@
#define SKEIN_BLK_TYPE_KEY (0) /* key, for MAC and KDF */ #define SKEIN_BLK_TYPE_KEY (0) /* key, for MAC and KDF */
#define SKEIN_BLK_TYPE_CFG (4) /* configuration block */ #define SKEIN_BLK_TYPE_CFG (4) /* configuration block */
#define SKEIN_BLK_TYPE_PERS (8) /* personalization string */ #define SKEIN_BLK_TYPE_PERS (8) /* personalization string */
#define SKEIN_BLK_TYPE_PK (12) /* public key (for signature hashing) */ #define SKEIN_BLK_TYPE_PK (12) /* public key (for hashing) */
#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ #define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */
#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ #define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */
#define SKEIN_BLK_TYPE_MSG (48) /* message processing */ #define SKEIN_BLK_TYPE_MSG (48) /* message processing */
@ -179,104 +216,27 @@
(hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height); \ (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height); \
} while (0) } while (0)
/*
* "Internal" Skein definitions for debugging and error checking
* Note: in Illumos we always disable debugging features.
*/
#define Skein_Show_Block(bits, ctx, X, blkPtr, wPtr, ksEvenPtr, ksOddPtr)
#define Skein_Show_Round(bits, ctx, r, X)
#define Skein_Show_R_Ptr(bits, ctx, r, X_ptr)
#define Skein_Show_Final(bits, ctx, cnt, outPtr)
#define Skein_Show_Key(bits, ctx, key, keyBytes)
/* run-time checks (e.g., bad params, uninitialized context)? */
#ifndef SKEIN_ERR_CHECK
/* default: ignore all Asserts, for performance */
#define Skein_Assert(x, retCode)
#define Skein_assert(x)
#elif defined(SKEIN_ASSERT)
#include <sys/debug.h>
#define Skein_Assert(x, retCode) ASSERT(x)
#define Skein_assert(x) ASSERT(x)
#else
#include <sys/debug.h>
/* caller error */
#define Skein_Assert(x, retCode) \
do { \
if (!(x)) \
return (retCode); \
} while (0)
/* internal error */
#define Skein_assert(x) ASSERT(x)
#endif
/* /*
* Skein block function constants (shared across Ref and Opt code) * Skein block function constants (shared across Ref and Opt code)
*/ */
enum { enum {
/* Skein_256 round rotation constants */
R_256_0_0 = 14, R_256_0_1 = 16,
R_256_1_0 = 52, R_256_1_1 = 57,
R_256_2_0 = 23, R_256_2_1 = 40,
R_256_3_0 = 5, R_256_3_1 = 37,
R_256_4_0 = 25, R_256_4_1 = 33,
R_256_5_0 = 46, R_256_5_1 = 12,
R_256_6_0 = 58, R_256_6_1 = 22,
R_256_7_0 = 32, R_256_7_1 = 32,
/* Skein_512 round rotation constants */ /* Skein_512 round rotation constants */
R_512_0_0 = 46, R_512_0_1 = 36, R_512_0_2 = 19, R_512_0_3 = 37, R_512_0_0 = 46, R_512_0_1 = 36, R_512_0_2 = 19, R_512_0_3 = 37,
R_512_1_0 = 33, R_512_1_1 = 27, R_512_1_2 = 14, R_512_1_3 = 42, R_512_1_0 = 33, R_512_1_1 = 27, R_512_1_2 = 14, R_512_1_3 = 42,
R_512_2_0 = 17, R_512_2_1 = 49, R_512_2_2 = 36, R_512_2_3 = 39, R_512_2_0 = 17, R_512_2_1 = 49, R_512_2_2 = 36, R_512_2_3 = 39,
R_512_3_0 = 44, R_512_3_1 = 9, R_512_3_2 = 54, R_512_3_3 = 56, R_512_3_0 = 44, R_512_3_1 = 9, R_512_3_2 = 54, R_512_3_3 = 56,
R_512_4_0 = 39, R_512_4_1 = 30, R_512_4_2 = 34, R_512_4_3 = 24, R_512_4_0 = 39, R_512_4_1 = 30, R_512_4_2 = 34, R_512_4_3 = 24,
R_512_5_0 = 13, R_512_5_1 = 50, R_512_5_2 = 10, R_512_5_3 = 17, R_512_5_0 = 13, R_512_5_1 = 50, R_512_5_2 = 10, R_512_5_3 = 17,
R_512_6_0 = 25, R_512_6_1 = 29, R_512_6_2 = 39, R_512_6_3 = 43, R_512_6_0 = 25, R_512_6_1 = 29, R_512_6_2 = 39, R_512_6_3 = 43,
R_512_7_0 = 8, R_512_7_1 = 35, R_512_7_2 = 56, R_512_7_3 = 22, R_512_7_0 = 8, R_512_7_1 = 35, R_512_7_2 = 56, R_512_7_3 = 22,
/* Skein1024 round rotation constants */
R1024_0_0 = 24, R1024_0_1 = 13, R1024_0_2 = 8, R1024_0_3 =
47, R1024_0_4 = 8, R1024_0_5 = 17, R1024_0_6 = 22, R1024_0_7 = 37,
R1024_1_0 = 38, R1024_1_1 = 19, R1024_1_2 = 10, R1024_1_3 =
55, R1024_1_4 = 49, R1024_1_5 = 18, R1024_1_6 = 23, R1024_1_7 = 52,
R1024_2_0 = 33, R1024_2_1 = 4, R1024_2_2 = 51, R1024_2_3 =
13, R1024_2_4 = 34, R1024_2_5 = 41, R1024_2_6 = 59, R1024_2_7 = 17,
R1024_3_0 = 5, R1024_3_1 = 20, R1024_3_2 = 48, R1024_3_3 =
41, R1024_3_4 = 47, R1024_3_5 = 28, R1024_3_6 = 16, R1024_3_7 = 25,
R1024_4_0 = 41, R1024_4_1 = 9, R1024_4_2 = 37, R1024_4_3 =
31, R1024_4_4 = 12, R1024_4_5 = 47, R1024_4_6 = 44, R1024_4_7 = 30,
R1024_5_0 = 16, R1024_5_1 = 34, R1024_5_2 = 56, R1024_5_3 =
51, R1024_5_4 = 4, R1024_5_5 = 53, R1024_5_6 = 42, R1024_5_7 = 41,
R1024_6_0 = 31, R1024_6_1 = 44, R1024_6_2 = 47, R1024_6_3 =
46, R1024_6_4 = 19, R1024_6_5 = 42, R1024_6_6 = 44, R1024_6_7 = 25,
R1024_7_0 = 9, R1024_7_1 = 48, R1024_7_2 = 35, R1024_7_3 =
52, R1024_7_4 = 23, R1024_7_5 = 31, R1024_7_6 = 37, R1024_7_7 = 20
}; };
/* number of rounds for the different block sizes */ /* number of rounds for the different block sizes */
#define SKEIN_256_ROUNDS_TOTAL (72)
#define SKEIN_512_ROUNDS_TOTAL (72) #define SKEIN_512_ROUNDS_TOTAL (72)
#define SKEIN1024_ROUNDS_TOTAL (80)
extern const uint64_t SKEIN_256_IV_128[];
extern const uint64_t SKEIN_256_IV_160[];
extern const uint64_t SKEIN_256_IV_224[];
extern const uint64_t SKEIN_256_IV_256[];
extern const uint64_t SKEIN_512_IV_224[];
extern const uint64_t SKEIN_512_IV_256[];
extern const uint64_t SKEIN_512_IV_384[];
extern const uint64_t SKEIN_512_IV_512[];
extern const uint64_t SKEIN1024_IV_384[];
extern const uint64_t SKEIN1024_IV_512[];
extern const uint64_t SKEIN1024_IV_1024[];
/* Functions to process blkCnt (nonzero) full block(s) of data. */ /* Functions to process blkCnt (nonzero) full block(s) of data. */
void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx, const uint8_t *blkPtr, extern void
size_t blkCnt, size_t byteCntAdd); Skein_512_Process_Block(SKEIN_CTX *ctx, const uint8_t *blkPtr,
void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
size_t blkCnt, size_t byteCntAdd);
void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx, const uint8_t *blkPtr,
size_t blkCnt, size_t byteCntAdd); size_t blkCnt, size_t byteCntAdd);
#endif /* _SKEIN_IMPL_H_ */ #endif /* _SKEIN_IMPL_H_ */

View File

@ -1,161 +0,0 @@
/*
* Pre-computed Skein IVs
*
* NOTE: these values are not "magic" constants, but
* are generated using the Threefish block function.
* They are pre-computed here only for speed; i.e., to
* avoid the need for a Threefish call during Init().
*
* The IV for any fixed hash length may be pre-computed.
* Only the most common values are included here.
*/
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
/*
* Illumos implementation note: these constants are for Skein v1.3 as per:
* http://www.skein-hash.info/sites/default/files/skein1.3.pdf
*/
#include <sys/skein.h> /* get Skein macros and types */
#include "skein_impl.h" /* get internal definitions */
#define MK_64 SKEIN_MK_64
/* blkSize = 256 bits. hashSize = 128 bits */
const uint64_t SKEIN_256_IV_128[] = {
MK_64(0xE1111906, 0x964D7260),
MK_64(0x883DAAA7, 0x7C8D811C),
MK_64(0x10080DF4, 0x91960F7A),
MK_64(0xCCF7DDE5, 0xB45BC1C2)
};
/* blkSize = 256 bits. hashSize = 160 bits */
const uint64_t SKEIN_256_IV_160[] = {
MK_64(0x14202314, 0x72825E98),
MK_64(0x2AC4E9A2, 0x5A77E590),
MK_64(0xD47A5856, 0x8838D63E),
MK_64(0x2DD2E496, 0x8586AB7D)
};
/* blkSize = 256 bits. hashSize = 224 bits */
const uint64_t SKEIN_256_IV_224[] = {
MK_64(0xC6098A8C, 0x9AE5EA0B),
MK_64(0x876D5686, 0x08C5191C),
MK_64(0x99CB88D7, 0xD7F53884),
MK_64(0x384BDDB1, 0xAEDDB5DE)
};
/* blkSize = 256 bits. hashSize = 256 bits */
const uint64_t SKEIN_256_IV_256[] = {
MK_64(0xFC9DA860, 0xD048B449),
MK_64(0x2FCA6647, 0x9FA7D833),
MK_64(0xB33BC389, 0x6656840F),
MK_64(0x6A54E920, 0xFDE8DA69)
};
/* blkSize = 512 bits. hashSize = 224 bits */
const uint64_t SKEIN_512_IV_224[] = {
MK_64(0xCCD06162, 0x48677224),
MK_64(0xCBA65CF3, 0xA92339EF),
MK_64(0x8CCD69D6, 0x52FF4B64),
MK_64(0x398AED7B, 0x3AB890B4),
MK_64(0x0F59D1B1, 0x457D2BD0),
MK_64(0x6776FE65, 0x75D4EB3D),
MK_64(0x99FBC70E, 0x997413E9),
MK_64(0x9E2CFCCF, 0xE1C41EF7)
};
/* blkSize = 512 bits. hashSize = 256 bits */
const uint64_t SKEIN_512_IV_256[] = {
MK_64(0xCCD044A1, 0x2FDB3E13),
MK_64(0xE8359030, 0x1A79A9EB),
MK_64(0x55AEA061, 0x4F816E6F),
MK_64(0x2A2767A4, 0xAE9B94DB),
MK_64(0xEC06025E, 0x74DD7683),
MK_64(0xE7A436CD, 0xC4746251),
MK_64(0xC36FBAF9, 0x393AD185),
MK_64(0x3EEDBA18, 0x33EDFC13)
};
/* blkSize = 512 bits. hashSize = 384 bits */
const uint64_t SKEIN_512_IV_384[] = {
MK_64(0xA3F6C6BF, 0x3A75EF5F),
MK_64(0xB0FEF9CC, 0xFD84FAA4),
MK_64(0x9D77DD66, 0x3D770CFE),
MK_64(0xD798CBF3, 0xB468FDDA),
MK_64(0x1BC4A666, 0x8A0E4465),
MK_64(0x7ED7D434, 0xE5807407),
MK_64(0x548FC1AC, 0xD4EC44D6),
MK_64(0x266E1754, 0x6AA18FF8)
};
/* blkSize = 512 bits. hashSize = 512 bits */
const uint64_t SKEIN_512_IV_512[] = {
MK_64(0x4903ADFF, 0x749C51CE),
MK_64(0x0D95DE39, 0x9746DF03),
MK_64(0x8FD19341, 0x27C79BCE),
MK_64(0x9A255629, 0xFF352CB1),
MK_64(0x5DB62599, 0xDF6CA7B0),
MK_64(0xEABE394C, 0xA9D5C3F4),
MK_64(0x991112C7, 0x1A75B523),
MK_64(0xAE18A40B, 0x660FCC33)
};
/* blkSize = 1024 bits. hashSize = 384 bits */
const uint64_t SKEIN1024_IV_384[] = {
MK_64(0x5102B6B8, 0xC1894A35),
MK_64(0xFEEBC9E3, 0xFE8AF11A),
MK_64(0x0C807F06, 0xE32BED71),
MK_64(0x60C13A52, 0xB41A91F6),
MK_64(0x9716D35D, 0xD4917C38),
MK_64(0xE780DF12, 0x6FD31D3A),
MK_64(0x797846B6, 0xC898303A),
MK_64(0xB172C2A8, 0xB3572A3B),
MK_64(0xC9BC8203, 0xA6104A6C),
MK_64(0x65909338, 0xD75624F4),
MK_64(0x94BCC568, 0x4B3F81A0),
MK_64(0x3EBBF51E, 0x10ECFD46),
MK_64(0x2DF50F0B, 0xEEB08542),
MK_64(0x3B5A6530, 0x0DBC6516),
MK_64(0x484B9CD2, 0x167BBCE1),
MK_64(0x2D136947, 0xD4CBAFEA)
};
/* blkSize = 1024 bits. hashSize = 512 bits */
const uint64_t SKEIN1024_IV_512[] = {
MK_64(0xCAEC0E5D, 0x7C1B1B18),
MK_64(0xA01B0E04, 0x5F03E802),
MK_64(0x33840451, 0xED912885),
MK_64(0x374AFB04, 0xEAEC2E1C),
MK_64(0xDF25A0E2, 0x813581F7),
MK_64(0xE4004093, 0x8B12F9D2),
MK_64(0xA662D539, 0xC2ED39B6),
MK_64(0xFA8B85CF, 0x45D8C75A),
MK_64(0x8316ED8E, 0x29EDE796),
MK_64(0x053289C0, 0x2E9F91B8),
MK_64(0xC3F8EF1D, 0x6D518B73),
MK_64(0xBDCEC3C4, 0xD5EF332E),
MK_64(0x549A7E52, 0x22974487),
MK_64(0x67070872, 0x5B749816),
MK_64(0xB9CD28FB, 0xF0581BD1),
MK_64(0x0E2940B8, 0x15804974)
};
/* blkSize = 1024 bits. hashSize = 1024 bits */
const uint64_t SKEIN1024_IV_1024[] = {
MK_64(0xD593DA07, 0x41E72355),
MK_64(0x15B5E511, 0xAC73E00C),
MK_64(0x5180E5AE, 0xBAF2C4F0),
MK_64(0x03BD41D3, 0xFCBCAFAF),
MK_64(0x1CAEC6FD, 0x1983A898),
MK_64(0x6E510B8B, 0xCDD0589F),
MK_64(0x77E2BDFD, 0xC6394ADA),
MK_64(0xC11E1DB5, 0x24DCB0A3),
MK_64(0xD6D14AF9, 0xC6329AB5),
MK_64(0x6A9B0BFC, 0x6EB67E0D),
MK_64(0x9243C60D, 0xCCFF1332),
MK_64(0x1A1F1DDE, 0x743F02D4),
MK_64(0x0996753C, 0x10ED0BB8),
MK_64(0x6572DD22, 0xF2B4969A),
MK_64(0x61FD3062, 0xD00A579A),
MK_64(0x1DE0536E, 0x8682E539)
};

View File

@ -1,116 +0,0 @@
/*
* Platform-specific definitions for Skein hash function.
*
* Source code author: Doug Whiting, 2008.
*
* This algorithm and source code is released to the public domain.
*
* Many thanks to Brian Gladman for his portable header files.
*
* To port Skein to an "unsupported" platform, change the definitions
* in this file appropriately.
*/
/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
#ifndef _SKEIN_PORT_H_
#define _SKEIN_PORT_H_
#include <sys/types.h> /* get integer type definitions */
#ifndef RotL_64
#define RotL_64(x, N) (((x) << (N)) | ((x) >> (64 - (N))))
#endif
/*
* Skein is "natively" little-endian (unlike SHA-xxx), for optimal
* performance on x86 CPUs. The Skein code requires the following
* definitions for dealing with endianness:
*
* SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian
* Skein_Put64_LSB_First
* Skein_Get64_LSB_First
* Skein_Swap64
*
* If SKEIN_NEED_SWAP is defined at compile time, it is used here
* along with the portable versions of Put64/Get64/Swap64, which
* are slow in general.
*
* Otherwise, an "auto-detect" of endianness is attempted below.
* If the default handling doesn't work well, the user may insert
* platform-specific code instead (e.g., for big-endian CPUs).
*
*/
#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
#include <sys/isa_defs.h> /* get endianness selection */
#if defined(_ZFS_BIG_ENDIAN)
/* here for big-endian CPUs */
#define SKEIN_NEED_SWAP (1)
#else
/* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
#define SKEIN_NEED_SWAP (0)
#define Skein_Put64_LSB_First(dst08, src64, bCnt) memcpy(dst08, src64, bCnt)
#define Skein_Get64_LSB_First(dst64, src08, wCnt) \
memcpy(dst64, src08, 8 * (wCnt))
#endif
#endif /* ifndef SKEIN_NEED_SWAP */
/*
* Provide any definitions still needed.
*/
#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */
#if SKEIN_NEED_SWAP
#define Skein_Swap64(w64) \
(((((uint64_t)(w64)) & 0xFF) << 56) | \
(((((uint64_t)(w64)) >> 8) & 0xFF) << 48) | \
(((((uint64_t)(w64)) >> 16) & 0xFF) << 40) | \
(((((uint64_t)(w64)) >> 24) & 0xFF) << 32) | \
(((((uint64_t)(w64)) >> 32) & 0xFF) << 24) | \
(((((uint64_t)(w64)) >> 40) & 0xFF) << 16) | \
(((((uint64_t)(w64)) >> 48) & 0xFF) << 8) | \
(((((uint64_t)(w64)) >> 56) & 0xFF)))
#else
#define Skein_Swap64(w64) (w64)
#endif
#endif /* ifndef Skein_Swap64 */
#ifndef Skein_Put64_LSB_First
static inline void
Skein_Put64_LSB_First(uint8_t *dst, const uint64_t *src, size_t bCnt)
{
/*
* this version is fully portable (big-endian or little-endian),
* but slow
*/
size_t n;
for (n = 0; n < bCnt; n++)
dst[n] = (uint8_t)(src[n >> 3] >> (8 * (n & 7)));
}
#endif /* ifndef Skein_Put64_LSB_First */
#ifndef Skein_Get64_LSB_First
static inline void
Skein_Get64_LSB_First(uint64_t *dst, const uint8_t *src, size_t wCnt)
{
/*
* this version is fully portable (big-endian or little-endian),
* but slow
*/
size_t n;
for (n = 0; n < 8 * wCnt; n += 8)
dst[n / 8] = (((uint64_t)src[n])) +
(((uint64_t)src[n + 1]) << 8) +
(((uint64_t)src[n + 2]) << 16) +
(((uint64_t)src[n + 3]) << 24) +
(((uint64_t)src[n + 4]) << 32) +
(((uint64_t)src[n + 5]) << 40) +
(((uint64_t)src[n + 6]) << 48) +
(((uint64_t)src[n + 7]) << 56);
}
#endif /* ifndef Skein_Get64_LSB_First */
#endif /* _SKEIN_PORT_H_ */

View File

@ -18,22 +18,22 @@
* *
* CDDL HEADER END * CDDL HEADER END
*/ */
/* /*
* Copyright 2013 Saso Kiselkov. All rights reserved. * Copyright (c) 2013 Saso Kiselkov. All rights reserved.
* Copyright (c) 2016 by Delphix. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved.
*/ */
#include <sys/zfs_context.h> #include <sys/zfs_context.h>
#include <sys/zio.h>
#include <sys/zio_checksum.h> #include <sys/zio_checksum.h>
#include <sys/skein.h> #include <sys/skein.h>
#include <sys/abd.h> #include <sys/abd.h>
static int static int
skein_incremental(void *buf, size_t size, void *arg) skein_incremental(void *buf, size_t size, void *arg)
{ {
Skein_512_Ctxt_t *ctx = arg; SKEIN_CTX *ctx = arg;
(void) Skein_512_Update(ctx, buf, size); Skein_512_Update(ctx, buf, size);
return (0); return (0);
} }
/* /*
@ -45,12 +45,12 @@ void
abd_checksum_skein_native(abd_t *abd, uint64_t size, abd_checksum_skein_native(abd_t *abd, uint64_t size,
const void *ctx_template, zio_cksum_t *zcp) const void *ctx_template, zio_cksum_t *zcp)
{ {
Skein_512_Ctxt_t ctx; SKEIN_CTX ctx;
ASSERT(ctx_template != NULL); ASSERT(ctx_template != NULL);
memcpy(&ctx, ctx_template, sizeof (ctx)); memcpy(&ctx, ctx_template, sizeof (ctx));
(void) abd_iterate_func(abd, 0, size, skein_incremental, &ctx); (void) abd_iterate_func(abd, 0, size, skein_incremental, &ctx);
(void) Skein_512_Final(&ctx, (uint8_t *)zcp); Skein_512_Final(&ctx, (uint8_t *)zcp);
memset(&ctx, 0, sizeof (ctx)); memset(&ctx, 0, sizeof (ctx));
} }
@ -79,9 +79,9 @@ abd_checksum_skein_byteswap(abd_t *abd, uint64_t size,
void * void *
abd_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt) abd_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt)
{ {
Skein_512_Ctxt_t *ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); SKEIN_CTX *ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
(void) Skein_512_InitExt(ctx, sizeof (zio_cksum_t) * 8, 0, Skein_512_InitExt(ctx, sizeof (zio_cksum_t) * 8, 0,
salt->zcs_bytes, sizeof (salt->zcs_bytes)); salt->zcs_bytes, sizeof (salt->zcs_bytes));
return (ctx); return (ctx);
} }
@ -93,7 +93,7 @@ abd_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt)
void void
abd_checksum_skein_tmpl_free(void *ctx_template) abd_checksum_skein_tmpl_free(void *ctx_template)
{ {
Skein_512_Ctxt_t *ctx = ctx_template; SKEIN_CTX *ctx = ctx_template;
memset(ctx, 0, sizeof (*ctx)); memset(ctx, 0, sizeof (*ctx));
kmem_free(ctx, sizeof (*ctx)); kmem_free(ctx, sizeof (*ctx));

View File

@ -38,7 +38,7 @@
/* /*
* Skein test suite using values from the Skein V1.3 specification found at: * Skein test suite using values from the Skein V1.3 specification found at:
* http://www.skein-hash.info/sites/default/files/skein1.3.pdf * https://www.schneier.com/wp-content/uploads/2015/01/skein.pdf
*/ */
/* /*
@ -48,13 +48,6 @@ static const uint8_t test_msg0[] = {
0xFF 0xFF
}; };
static const uint8_t test_msg1[] = {
0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0
};
static const uint8_t test_msg2[] = { static const uint8_t test_msg2[] = {
0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
@ -85,69 +78,9 @@ static const uint8_t test_msg3[] = {
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
}; };
static const uint8_t test_msg4[] = {
0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0,
0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8,
0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0,
0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8,
0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0,
0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78,
0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68,
0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58,
0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28,
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
};
/* /*
* Test digests from the Skein spec, Appendix C. * Test digests from the Skein spec, Appendix C.
*/ */
static const uint8_t skein_256_test_digests[][32] = {
{
/* for test_msg0 */
0x0B, 0x98, 0xDC, 0xD1, 0x98, 0xEA, 0x0E, 0x50,
0xA7, 0xA2, 0x44, 0xC4, 0x44, 0xE2, 0x5C, 0x23,
0xDA, 0x30, 0xC1, 0x0F, 0xC9, 0xA1, 0xF2, 0x70,
0xA6, 0x63, 0x7F, 0x1F, 0x34, 0xE6, 0x7E, 0xD2
},
{
/* for test_msg1 */
0x8D, 0x0F, 0xA4, 0xEF, 0x77, 0x7F, 0xD7, 0x59,
0xDF, 0xD4, 0x04, 0x4E, 0x6F, 0x6A, 0x5A, 0xC3,
0xC7, 0x74, 0xAE, 0xC9, 0x43, 0xDC, 0xFC, 0x07,
0x92, 0x7B, 0x72, 0x3B, 0x5D, 0xBF, 0x40, 0x8B
},
{
/* for test_msg2 */
0xDF, 0x28, 0xE9, 0x16, 0x63, 0x0D, 0x0B, 0x44,
0xC4, 0xA8, 0x49, 0xDC, 0x9A, 0x02, 0xF0, 0x7A,
0x07, 0xCB, 0x30, 0xF7, 0x32, 0x31, 0x82, 0x56,
0xB1, 0x5D, 0x86, 0x5A, 0xC4, 0xAE, 0x16, 0x2F
}
/* no test digests for test_msg3 and test_msg4 */
};
static const uint8_t skein_512_test_digests[][64] = { static const uint8_t skein_512_test_digests[][64] = {
{ {
/* for test_msg0 */ /* for test_msg0 */
@ -189,74 +122,6 @@ static const uint8_t skein_512_test_digests[][64] = {
/* no test digests for test_msg4 */ /* no test digests for test_msg4 */
}; };
static const uint8_t skein_1024_test_digests[][128] = {
{
/* for test_msg0 */
0xE6, 0x2C, 0x05, 0x80, 0x2E, 0xA0, 0x15, 0x24,
0x07, 0xCD, 0xD8, 0x78, 0x7F, 0xDA, 0x9E, 0x35,
0x70, 0x3D, 0xE8, 0x62, 0xA4, 0xFB, 0xC1, 0x19,
0xCF, 0xF8, 0x59, 0x0A, 0xFE, 0x79, 0x25, 0x0B,
0xCC, 0xC8, 0xB3, 0xFA, 0xF1, 0xBD, 0x24, 0x22,
0xAB, 0x5C, 0x0D, 0x26, 0x3F, 0xB2, 0xF8, 0xAF,
0xB3, 0xF7, 0x96, 0xF0, 0x48, 0x00, 0x03, 0x81,
0x53, 0x1B, 0x6F, 0x00, 0xD8, 0x51, 0x61, 0xBC,
0x0F, 0xFF, 0x4B, 0xEF, 0x24, 0x86, 0xB1, 0xEB,
0xCD, 0x37, 0x73, 0xFA, 0xBF, 0x50, 0xAD, 0x4A,
0xD5, 0x63, 0x9A, 0xF9, 0x04, 0x0E, 0x3F, 0x29,
0xC6, 0xC9, 0x31, 0x30, 0x1B, 0xF7, 0x98, 0x32,
0xE9, 0xDA, 0x09, 0x85, 0x7E, 0x83, 0x1E, 0x82,
0xEF, 0x8B, 0x46, 0x91, 0xC2, 0x35, 0x65, 0x65,
0x15, 0xD4, 0x37, 0xD2, 0xBD, 0xA3, 0x3B, 0xCE,
0xC0, 0x01, 0xC6, 0x7F, 0xFD, 0xE1, 0x5B, 0xA8
},
{
/* no test vector for test_msg1 */
0
},
{
/* no test vector for test_msg2 */
0
},
{
/* for test_msg3 */
0x1F, 0x3E, 0x02, 0xC4, 0x6F, 0xB8, 0x0A, 0x3F,
0xCD, 0x2D, 0xFB, 0xBC, 0x7C, 0x17, 0x38, 0x00,
0xB4, 0x0C, 0x60, 0xC2, 0x35, 0x4A, 0xF5, 0x51,
0x18, 0x9E, 0xBF, 0x43, 0x3C, 0x3D, 0x85, 0xF9,
0xFF, 0x18, 0x03, 0xE6, 0xD9, 0x20, 0x49, 0x31,
0x79, 0xED, 0x7A, 0xE7, 0xFC, 0xE6, 0x9C, 0x35,
0x81, 0xA5, 0xA2, 0xF8, 0x2D, 0x3E, 0x0C, 0x7A,
0x29, 0x55, 0x74, 0xD0, 0xCD, 0x7D, 0x21, 0x7C,
0x48, 0x4D, 0x2F, 0x63, 0x13, 0xD5, 0x9A, 0x77,
0x18, 0xEA, 0xD0, 0x7D, 0x07, 0x29, 0xC2, 0x48,
0x51, 0xD7, 0xE7, 0xD2, 0x49, 0x1B, 0x90, 0x2D,
0x48, 0x91, 0x94, 0xE6, 0xB7, 0xD3, 0x69, 0xDB,
0x0A, 0xB7, 0xAA, 0x10, 0x6F, 0x0E, 0xE0, 0xA3,
0x9A, 0x42, 0xEF, 0xC5, 0x4F, 0x18, 0xD9, 0x37,
0x76, 0x08, 0x09, 0x85, 0xF9, 0x07, 0x57, 0x4F,
0x99, 0x5E, 0xC6, 0xA3, 0x71, 0x53, 0xA5, 0x78
},
{
/* for test_msg4 */
0x84, 0x2A, 0x53, 0xC9, 0x9C, 0x12, 0xB0, 0xCF,
0x80, 0xCF, 0x69, 0x49, 0x1B, 0xE5, 0xE2, 0xF7,
0x51, 0x5D, 0xE8, 0x73, 0x3B, 0x6E, 0xA9, 0x42,
0x2D, 0xFD, 0x67, 0x66, 0x65, 0xB5, 0xFA, 0x42,
0xFF, 0xB3, 0xA9, 0xC4, 0x8C, 0x21, 0x77, 0x77,
0x95, 0x08, 0x48, 0xCE, 0xCD, 0xB4, 0x8F, 0x64,
0x0F, 0x81, 0xFB, 0x92, 0xBE, 0xF6, 0xF8, 0x8F,
0x7A, 0x85, 0xC1, 0xF7, 0xCD, 0x14, 0x46, 0xC9,
0x16, 0x1C, 0x0A, 0xFE, 0x8F, 0x25, 0xAE, 0x44,
0x4F, 0x40, 0xD3, 0x68, 0x00, 0x81, 0xC3, 0x5A,
0xA4, 0x3F, 0x64, 0x0F, 0xD5, 0xFA, 0x3C, 0x3C,
0x03, 0x0B, 0xCC, 0x06, 0xAB, 0xAC, 0x01, 0xD0,
0x98, 0xBC, 0xC9, 0x84, 0xEB, 0xD8, 0x32, 0x27,
0x12, 0x92, 0x1E, 0x00, 0xB1, 0xBA, 0x07, 0xD6,
0xD0, 0x1F, 0x26, 0x90, 0x70, 0x50, 0x25, 0x5E,
0xF2, 0xC8, 0xE2, 0x4F, 0x71, 0x6C, 0x52, 0xA5
}
};
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -268,11 +133,11 @@ main(int argc, char *argv[])
#define SKEIN_ALGO_TEST(_m, mode, diglen, testdigest) \ #define SKEIN_ALGO_TEST(_m, mode, diglen, testdigest) \
do { \ do { \
Skein ## mode ## _Ctxt_t ctx; \ SKEIN_CTX ctx; \
uint8_t digest[diglen / 8]; \ uint8_t digest[diglen / 8]; \
(void) Skein ## mode ## _Init(&ctx, diglen); \ Skein ## mode ## _Init(&ctx, diglen); \
(void) Skein ## mode ## _Update(&ctx, _m, sizeof (_m)); \ Skein ## mode ## _Update(&ctx, _m, sizeof (_m)); \
(void) Skein ## mode ## _Final(&ctx, digest); \ Skein ## mode ## _Final(&ctx, digest); \
(void) printf("Skein" #mode "/" #diglen \ (void) printf("Skein" #mode "/" #diglen \
"\tMessage: " #_m "\tResult: "); \ "\tMessage: " #_m "\tResult: "); \
if (memcmp(digest, testdigest, diglen / 8) == 0) { \ if (memcmp(digest, testdigest, diglen / 8) == 0) { \
@ -285,7 +150,7 @@ main(int argc, char *argv[])
#define SKEIN_PERF_TEST(mode, diglen) \ #define SKEIN_PERF_TEST(mode, diglen) \
do { \ do { \
Skein ## mode ## _Ctxt_t ctx; \ SKEIN_CTX ctx; \
uint8_t digest[diglen / 8]; \ uint8_t digest[diglen / 8]; \
uint8_t block[131072]; \ uint8_t block[131072]; \
uint64_t delta; \ uint64_t delta; \
@ -294,12 +159,12 @@ main(int argc, char *argv[])
struct timeval start, end; \ struct timeval start, end; \
memset(block, 0, sizeof (block)); \ memset(block, 0, sizeof (block)); \
(void) gettimeofday(&start, NULL); \ (void) gettimeofday(&start, NULL); \
(void) Skein ## mode ## _Init(&ctx, diglen); \ Skein ## mode ## _Init(&ctx, diglen); \
for (i = 0; i < 8192; i++) { \ for (i = 0; i < 8192; i++) { \
(void) Skein ## mode ## _Update(&ctx, block, \ Skein ## mode ## _Update(&ctx, block, \
sizeof (block)); \ sizeof (block)); \
} \ } \
(void) Skein ## mode ## _Final(&ctx, digest); \ Skein ## mode ## _Final(&ctx, digest); \
(void) gettimeofday(&end, NULL); \ (void) gettimeofday(&end, NULL); \
delta = (end.tv_sec * 1000000llu + end.tv_usec) - \ delta = (end.tv_sec * 1000000llu + end.tv_usec) - \
(start.tv_sec * 1000000llu + start.tv_usec); \ (start.tv_sec * 1000000llu + start.tv_usec); \
@ -312,23 +177,15 @@ main(int argc, char *argv[])
} while (0) } while (0)
(void) printf("Running algorithm correctness tests:\n"); (void) printf("Running algorithm correctness tests:\n");
SKEIN_ALGO_TEST(test_msg0, _256, 256, skein_256_test_digests[0]);
SKEIN_ALGO_TEST(test_msg1, _256, 256, skein_256_test_digests[1]);
SKEIN_ALGO_TEST(test_msg2, _256, 256, skein_256_test_digests[2]);
SKEIN_ALGO_TEST(test_msg0, _512, 512, skein_512_test_digests[0]); SKEIN_ALGO_TEST(test_msg0, _512, 512, skein_512_test_digests[0]);
SKEIN_ALGO_TEST(test_msg2, _512, 512, skein_512_test_digests[2]); SKEIN_ALGO_TEST(test_msg2, _512, 512, skein_512_test_digests[2]);
SKEIN_ALGO_TEST(test_msg3, _512, 512, skein_512_test_digests[3]); SKEIN_ALGO_TEST(test_msg3, _512, 512, skein_512_test_digests[3]);
SKEIN_ALGO_TEST(test_msg0, 1024, 1024, skein_1024_test_digests[0]);
SKEIN_ALGO_TEST(test_msg3, 1024, 1024, skein_1024_test_digests[3]);
SKEIN_ALGO_TEST(test_msg4, 1024, 1024, skein_1024_test_digests[4]);
if (failed) if (failed)
return (1); return (1);
(void) printf("Running performance tests (hashing 1024 MiB of " (void) printf("Running performance tests (hashing 1024 MiB of "
"data):\n"); "data):\n");
SKEIN_PERF_TEST(_256, 256);
SKEIN_PERF_TEST(_512, 512); SKEIN_PERF_TEST(_512, 512);
SKEIN_PERF_TEST(1024, 1024);
return (0); return (0);
} }