├── .gitignore ├── .hgignore ├── Makefile ├── README.org ├── c_src ├── brg_endian.h ├── brg_types.h ├── erl_nif_compat.h ├── skein.c ├── skein.h ├── skein_api.c ├── skein_api.h ├── skein_block.c ├── skein_debug.c ├── skein_debug.h ├── skein_iv.h ├── skein_port.h └── skerl_nifs.c ├── ebin └── skerl.app ├── rebar ├── rebar.config ├── src ├── hex.erl └── skerl.erl └── test └── skerl_tests.erl /.gitignore: -------------------------------------------------------------------------------- 1 | c_src/*.o 2 | .eunit 3 | ebin/*.beam 4 | priv/*.so -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | .eunit/.*$ 2 | c_src/.*\.o$ 3 | priv/.*\.so$ 4 | ebin/.*\.beam$ 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ./rebar compile 3 | 4 | clean: 5 | ./rebar clean 6 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * skerl 2 | ** Overview 3 | =skerl= is a NIF wrapper around Skein hashing functions 4 | 5 | ** Quick Start 6 | You must have [[http://erlang.org/download.html][Erlang/OTP R13B04]] or later and a GNU-style build 7 | system to compile and run =skerl=. 8 | 9 | #+BEGIN_SRC shell 10 | git clone git://github.com/basho/skerl.git 11 | cd skerl 12 | make 13 | #+END_SRC 14 | 15 | Start up an Erlang shell with the path to =skerl= included. 16 | 17 | #+BEGIN_SRC shell 18 | cd path/to/skerl/ebin 19 | erl 20 | #+END_SRC 21 | 22 | Hash a binary by calling =skerl:hash/2= with the desired number of 23 | bits for the resulting hash: 24 | 25 | #+BEGIN_SRC erlang 26 | 1> Bits = 256. 27 | 256 28 | 2> Data = <<"foobarbazquux">>. 29 | <<"foobarbazquux">> 30 | 3> {ok, Hash} = skerl:hash(Bits, Data). 31 | {ok,<<206,36,175,108,168,91,124,11,181,108,144,164,36, 32 | 216,130,110,241,197,98,180,65,120,56,225,1,255,54, 33 | ...>>} 34 | 4> bit_size(Hash). 35 | 256 36 | #+END_SRC 37 | 38 | You may find =skerl:hexhash/2= more useful, as it returns a 39 | hexadecimal-encoded string representing the hash: 40 | 41 | #+BEGIN_SRC erlang 42 | 5> HexHash = skerl:hexhash(Bits, Data). 43 | <<"ce24af6ca85b7c0bb56c90a424d8826ef1c562b4417838e101ff3627dcc000bc">> 44 | #+END_SRC 45 | 46 | ** The Skein Hash 47 | 48 | The underlying hashing code in Skerl is the reference implementation 49 | of Skein from the official NIST submission. 50 | 51 | Skein is a [[http://csrc.nist.gov/groups/ST/hash/sha-3/Round3/submissions_rnd3.html][finalist candidate in the NIST competition to become SHA-3]]. 52 | 53 | It is a hash function designed by 54 | Niels Ferguson, Stefan Lucks, Bruce Schneier, Doug Whiting, Mihir 55 | Bellare, Tadayoshi Kohno, Jon Callas, and Jesse Walker. 56 | 57 | Details on the algorithm as submitted and known analysis can be found 58 | at [[http://ehash.iaik.tugraz.at/wiki/Skein][ecrypt]]. 59 | 60 | A [[http://www.schneier.com/skein1.3.pdf][full paper on Skein]] 61 | by the designers has been published. 62 | 63 | The [[http://www.skein-hash.info/][official Skein page]] uses the headline: 64 | 65 | Fast, Secure, Simple, Flexible, Efficient. And it rhymes with "rain." 66 | 67 | ** Contributing 68 | We encourage contributions to =skerl= from the community. 69 | 70 | 1) Fork the =skerl= repository on [[https://github.com/basho/skerl][Github]]. 71 | 2) Clone your fork or add the remote if you already have a clone of 72 | the repository. 73 | #+BEGIN_SRC shell 74 | git clone git@github.com:yourusername/skerl.git 75 | # or 76 | git remote add mine git@github.com:yourusername/skerl.git 77 | #+END_SRC 78 | 3) Create a topic branch for your change. 79 | #+BEGIN_SRC shell 80 | git checkout -b some-topic-branch 81 | #+END_SRC 82 | 4) Make your change and commit. Use a clear and descriptive commit 83 | message, spanning multiple lines if detailed explanation is 84 | needed. 85 | 5) Push to your fork of the repository and then send a pull-request 86 | through Github. 87 | #+BEGIN_SRC shell 88 | git push mine some-topic-branch 89 | #+END_SRC 90 | 6) A Basho engineer or community maintainer will review your patch 91 | and merge it into the main repository or send you feedback. 92 | 93 | -------------------------------------------------------------------------------- /c_src/brg_endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------------------------------------------------- 3 | Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved. 4 | 5 | LICENSE TERMS 6 | 7 | The free distribution and use of this software in both source and binary 8 | form is allowed (with or without changes) provided that: 9 | 10 | 1. distributions of this source code include the above copyright 11 | notice, this list of conditions and the following disclaimer; 12 | 13 | 2. distributions in binary form include the above copyright 14 | notice, this list of conditions and the following disclaimer 15 | in the documentation and/or other associated materials; 16 | 17 | 3. the copyright holder's name is not used to endorse products 18 | built using this software without specific written permission. 19 | 20 | ALTERNATIVELY, provided that this notice is retained in full, this product 21 | may be distributed under the terms of the GNU General Public License (GPL), 22 | in which case the provisions of the GPL apply INSTEAD OF those given above. 23 | 24 | DISCLAIMER 25 | 26 | This software is provided 'as is' with no explicit or implied warranties 27 | in respect of its properties, including, but not limited to, correctness 28 | and/or fitness for purpose. 29 | --------------------------------------------------------------------------- 30 | Issue 20/10/2006 31 | */ 32 | 33 | /* modified by justin@basho.com to include Solaris endianness test */ 34 | 35 | #ifndef BRG_ENDIAN_H 36 | #define BRG_ENDIAN_H 37 | 38 | #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ 39 | #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ 40 | 41 | /* Include files where endian defines and byteswap functions may reside */ 42 | #if defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) || \ 43 | defined( __DragonFly__ ) 44 | # include 45 | # include 46 | #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ 47 | defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) 48 | # include 49 | #elif defined (__SVR4) && defined (__sun) 50 | # ifdef __sparc__ 51 | # define BYTE_ORDER IS_BIG_ENDIAN 52 | # else 53 | # define BYTE_ORDER IS_LITTLE_ENDIAN 54 | # endif 55 | #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) 56 | # if !defined( __MINGW32__ ) && !defined(AVR) 57 | # include 58 | # if !defined( __BEOS__ ) 59 | # include 60 | # endif 61 | # endif 62 | #endif 63 | 64 | /* Now attempt to set the define for platform byte order using any */ 65 | /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ 66 | /* seem to encompass most endian symbol definitions */ 67 | 68 | #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) 69 | # if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN 70 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 71 | # elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN 72 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 73 | # endif 74 | #elif defined( BIG_ENDIAN ) 75 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 76 | #elif defined( LITTLE_ENDIAN ) 77 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 78 | #endif 79 | 80 | #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) 81 | # if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN 82 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 83 | # elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN 84 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 85 | # endif 86 | #elif defined( _BIG_ENDIAN ) 87 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 88 | #elif defined( _LITTLE_ENDIAN ) 89 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 90 | #endif 91 | 92 | #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) 93 | # if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN 94 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 95 | # elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN 96 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 97 | # endif 98 | #elif defined( __BIG_ENDIAN ) 99 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 100 | #elif defined( __LITTLE_ENDIAN ) 101 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 102 | #endif 103 | 104 | #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) 105 | # if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ 106 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 107 | # elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ 108 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 109 | # endif 110 | #elif defined( __BIG_ENDIAN__ ) 111 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 112 | #elif defined( __LITTLE_ENDIAN__ ) 113 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 114 | #endif 115 | 116 | /* if the platform byte order could not be determined, then try to */ 117 | /* set this define using common machine defines */ 118 | #if !defined(PLATFORM_BYTE_ORDER) 119 | 120 | #if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ 121 | defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ 122 | defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ 123 | defined( vax ) || defined( vms ) || defined( VMS ) || \ 124 | defined( __VMS ) || defined( _M_X64 ) || defined( AVR ) 125 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 126 | 127 | #elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ 128 | defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ 129 | defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ 130 | defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ 131 | defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ 132 | defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ 133 | defined( THINK_C ) || defined( __VMCMS__ ) 134 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 135 | 136 | #elif 0 /* **** EDIT HERE IF NECESSARY **** */ 137 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 138 | #elif 0 /* **** EDIT HERE IF NECESSARY **** */ 139 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 140 | #else 141 | # error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order 142 | #endif 143 | #endif 144 | 145 | /* special handler for IA64, which may be either endianness (?) */ 146 | /* here we assume little-endian, but this may need to be changed */ 147 | #if defined(__ia64) || defined(__ia64__) || defined(_M_IA64) 148 | # define PLATFORM_MUST_ALIGN (1) 149 | #ifndef PLATFORM_BYTE_ORDER 150 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 151 | #endif 152 | #endif 153 | 154 | #ifndef PLATFORM_MUST_ALIGN 155 | # define PLATFORM_MUST_ALIGN (0) 156 | #endif 157 | 158 | #endif /* ifndef BRG_ENDIAN_H */ 159 | -------------------------------------------------------------------------------- /c_src/brg_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------------------------------------------------- 3 | Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved. 4 | 5 | LICENSE TERMS 6 | 7 | The free distribution and use of this software in both source and binary 8 | form is allowed (with or without changes) provided that: 9 | 10 | 1. distributions of this source code include the above copyright 11 | notice, this list of conditions and the following disclaimer; 12 | 13 | 2. distributions in binary form include the above copyright 14 | notice, this list of conditions and the following disclaimer 15 | in the documentation and/or other associated materials; 16 | 17 | 3. the copyright holder's name is not used to endorse products 18 | built using this software without specific written permission. 19 | 20 | ALTERNATIVELY, provided that this notice is retained in full, this product 21 | may be distributed under the terms of the GNU General Public License (GPL), 22 | in which case the provisions of the GPL apply INSTEAD OF those given above. 23 | 24 | DISCLAIMER 25 | 26 | This software is provided 'as is' with no explicit or implied warranties 27 | in respect of its properties, including, but not limited to, correctness 28 | and/or fitness for purpose. 29 | --------------------------------------------------------------------------- 30 | Issue 09/09/2006 31 | 32 | The unsigned integer types defined here are of the form uint_t where 33 | is the length of the type; for example, the unsigned 32-bit type is 34 | 'uint_32t'. These are NOT the same as the 'C99 integer types' that are 35 | defined in the inttypes.h and stdint.h headers since attempts to use these 36 | types have shown that support for them is still highly variable. However, 37 | since the latter are of the form uint_t, a regular expression search 38 | and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') 39 | can be used to convert the types used here to the C99 standard types. 40 | */ 41 | 42 | #ifndef BRG_TYPES_H 43 | #define BRG_TYPES_H 44 | 45 | #if defined(__cplusplus) 46 | extern "C" { 47 | #endif 48 | 49 | #include 50 | 51 | #ifndef BRG_UI8 52 | # define BRG_UI8 53 | # if UCHAR_MAX == 255u 54 | typedef unsigned char uint_8t; 55 | # else 56 | # error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h 57 | # endif 58 | #endif 59 | 60 | #ifndef BRG_UI16 61 | # define BRG_UI16 62 | # if USHRT_MAX == 65535u 63 | typedef unsigned short uint_16t; 64 | # else 65 | # error Please define uint_16t as a 16-bit unsigned short type in brg_types.h 66 | # endif 67 | #endif 68 | 69 | #ifndef BRG_UI32 70 | # define BRG_UI32 71 | # if UINT_MAX == 4294967295u 72 | # define li_32(h) 0x##h##u 73 | typedef unsigned int uint_32t; 74 | # elif ULONG_MAX == 4294967295u 75 | # define li_32(h) 0x##h##ul 76 | typedef unsigned long uint_32t; 77 | # elif defined( _CRAY ) 78 | # error This code needs 32-bit data types, which Cray machines do not provide 79 | # else 80 | # error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h 81 | # endif 82 | #endif 83 | 84 | #ifndef BRG_UI64 85 | # if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) 86 | # define BRG_UI64 87 | # define li_64(h) 0x##h##ui64 88 | typedef unsigned __int64 uint_64t; 89 | # elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ 90 | # define BRG_UI64 91 | # define li_64(h) 0x##h##ui64 92 | typedef unsigned __int64 uint_64t; 93 | # elif defined( __sun ) && defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful 94 | # define BRG_UI64 95 | # define li_64(h) 0x##h##ull 96 | typedef unsigned long long uint_64t; 97 | # elif defined( UINT_MAX ) && UINT_MAX > 4294967295u 98 | # if UINT_MAX == 18446744073709551615u 99 | # define BRG_UI64 100 | # define li_64(h) 0x##h##u 101 | typedef unsigned int uint_64t; 102 | # endif 103 | # elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u 104 | # if ULONG_MAX == 18446744073709551615ul 105 | # define BRG_UI64 106 | # define li_64(h) 0x##h##ul 107 | typedef unsigned long uint_64t; 108 | # endif 109 | # elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u 110 | # if ULLONG_MAX == 18446744073709551615ull 111 | # define BRG_UI64 112 | # define li_64(h) 0x##h##ull 113 | typedef unsigned long long uint_64t; 114 | # endif 115 | # elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u 116 | # if ULONG_LONG_MAX == 18446744073709551615ull 117 | # define BRG_UI64 118 | # define li_64(h) 0x##h##ull 119 | typedef unsigned long long uint_64t; 120 | # endif 121 | # elif defined(__GNUC__) /* DLW: avoid mingw problem with -ansi */ 122 | # define BRG_UI64 123 | # define li_64(h) 0x##h##ull 124 | typedef unsigned long long uint_64t; 125 | # endif 126 | #endif 127 | 128 | #if defined( NEED_UINT_64T ) && !defined( BRG_UI64 ) 129 | # error Please define uint_64t as an unsigned 64 bit type in brg_types.h 130 | #endif 131 | 132 | #ifndef RETURN_VALUES 133 | # define RETURN_VALUES 134 | # if defined( DLL_EXPORT ) 135 | # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) 136 | # define VOID_RETURN __declspec( dllexport ) void __stdcall 137 | # define INT_RETURN __declspec( dllexport ) int __stdcall 138 | # elif defined( __GNUC__ ) 139 | # define VOID_RETURN __declspec( __dllexport__ ) void 140 | # define INT_RETURN __declspec( __dllexport__ ) int 141 | # else 142 | # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers 143 | # endif 144 | # elif defined( DLL_IMPORT ) 145 | # if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) 146 | # define VOID_RETURN __declspec( dllimport ) void __stdcall 147 | # define INT_RETURN __declspec( dllimport ) int __stdcall 148 | # elif defined( __GNUC__ ) 149 | # define VOID_RETURN __declspec( __dllimport__ ) void 150 | # define INT_RETURN __declspec( __dllimport__ ) int 151 | # else 152 | # error Use of the DLL is only available on the Microsoft, Intel and GCC compilers 153 | # endif 154 | # elif defined( __WATCOMC__ ) 155 | # define VOID_RETURN void __cdecl 156 | # define INT_RETURN int __cdecl 157 | # else 158 | # define VOID_RETURN void 159 | # define INT_RETURN int 160 | # endif 161 | #endif 162 | 163 | /* These defines are used to declare buffers in a way that allows 164 | faster operations on longer variables to be used. In all these 165 | defines 'size' must be a power of 2 and >= 8 166 | 167 | dec_unit_type(size,x) declares a variable 'x' of length 168 | 'size' bits 169 | 170 | dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize' 171 | bytes defined as an array of variables 172 | each of 'size' bits (bsize must be a 173 | multiple of size / 8) 174 | 175 | ptr_cast(x,size) casts a pointer to a pointer to a 176 | varaiable of length 'size' bits 177 | */ 178 | 179 | #define ui_type(size) uint_##size##t 180 | #define dec_unit_type(size,x) typedef ui_type(size) x 181 | #define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)] 182 | #define ptr_cast(x,size) ((ui_type(size)*)(x)) 183 | 184 | #if defined(__cplusplus) 185 | } 186 | #endif 187 | 188 | #endif 189 | -------------------------------------------------------------------------------- /c_src/erl_nif_compat.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010-2011 Basho Technologies, Inc. 2 | * 3 | * This file is provided to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file 5 | * except in compliance with the License. You may obtain 6 | * a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | */ 17 | 18 | #ifndef ERL_NIF_COMPAT_H_ 19 | #define ERL_NIF_COMPAT_H_ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif /* __cplusplus */ 24 | 25 | #include "erl_nif.h" 26 | 27 | #if ERL_NIF_MAJOR_VERSION == 1 && ERL_NIF_MINOR_VERSION == 0 28 | 29 | #define enif_open_resource_type_compat enif_open_resource_type 30 | #define enif_alloc_resource_compat enif_alloc_resource 31 | #define enif_release_resource_compat enif_release_resource 32 | #define enif_alloc_binary_compat enif_alloc_binary 33 | #define enif_alloc_compat enif_alloc 34 | #define enif_free_compat enif_free 35 | #define enif_cond_create erl_drv_cond_create 36 | #define enif_cond_destroy erl_drv_cond_destroy 37 | #define enif_cond_signal erl_drv_cond_signal 38 | #define enif_cond_broadcast erl_drv_cond_broadcast 39 | #define enif_cond_wait erl_drv_cond_wait 40 | #define ErlNifCond ErlDrvCond 41 | #endif /* R13B04 */ 42 | 43 | #if ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 0 44 | 45 | #define enif_open_resource_type_compat(E, N, D, F, T) \ 46 | enif_open_resource_type(E, NULL, N, D, F, T) 47 | 48 | #define enif_alloc_resource_compat(E, T, S) \ 49 | enif_alloc_resource(T, S) 50 | 51 | #define enif_release_resource_compat(E, H) \ 52 | enif_release_resource(H) 53 | 54 | #define enif_alloc_binary_compat(E, S, B) \ 55 | enif_alloc_binary(S, B) 56 | 57 | #define enif_alloc_compat(E, S) \ 58 | enif_alloc(S) 59 | 60 | #define enif_free_compat(E, P) \ 61 | enif_free(P) 62 | 63 | #endif /* R14 */ 64 | 65 | 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif /* __cplusplus */ 70 | 71 | #endif /* ERL_NIF_COMPAT_H_ */ 72 | -------------------------------------------------------------------------------- /c_src/skein.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | ** 3 | ** Implementation of the Skein hash function. 4 | ** 5 | ** Source code author: Doug Whiting, 2008. 6 | ** 7 | ** This algorithm and source code is released to the public domain. 8 | ** 9 | ************************************************************************/ 10 | 11 | #define SKEIN_PORT_CODE /* instantiate any code in skein_port.h */ 12 | 13 | #include /* get the memcpy/memset functions */ 14 | #include "skein.h" /* get the Skein API definitions */ 15 | #include "skein_iv.h" /* get precomputed IVs */ 16 | 17 | /*****************************************************************/ 18 | /* External function to process blkCnt (nonzero) full block(s) of data. */ 19 | void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); 20 | void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); 21 | void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd); 22 | 23 | /*****************************************************************/ 24 | /* 256-bit Skein */ 25 | /*****************************************************************/ 26 | 27 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 28 | /* init the context for a straight hashing operation */ 29 | int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen) 30 | { 31 | union 32 | { 33 | u08b_t b[SKEIN_256_STATE_BYTES]; 34 | u64b_t w[SKEIN_256_STATE_WORDS]; 35 | } cfg; /* config block */ 36 | 37 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 38 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 39 | 40 | switch (hashBitLen) 41 | { /* use pre-computed values, where available */ 42 | #ifndef SKEIN_NO_PRECOMP 43 | case 256: memcpy(ctx->X,SKEIN_256_IV_256,sizeof(ctx->X)); break; 44 | case 224: memcpy(ctx->X,SKEIN_256_IV_224,sizeof(ctx->X)); break; 45 | case 160: memcpy(ctx->X,SKEIN_256_IV_160,sizeof(ctx->X)); break; 46 | case 128: memcpy(ctx->X,SKEIN_256_IV_128,sizeof(ctx->X)); break; 47 | #endif 48 | default: 49 | /* here if there is no precomputed IV value available */ 50 | /* build/process the config block, type == CONFIG (could be precomputed) */ 51 | Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ 52 | 53 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ 54 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 55 | cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); 56 | memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ 57 | 58 | /* compute the initial chaining values from config block */ 59 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ 60 | Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 61 | break; 62 | } 63 | /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ 64 | /* Set up to process the data message portion of the hash (default) */ 65 | Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ 66 | 67 | return SKEIN_SUCCESS; 68 | } 69 | 70 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 71 | /* init the context for a MAC and/or tree hash operation */ 72 | /* [identical to Skein_256_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ 73 | int Skein_256_InitExt(Skein_256_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) 74 | { 75 | union 76 | { 77 | u08b_t b[SKEIN_256_STATE_BYTES]; 78 | u64b_t w[SKEIN_256_STATE_WORDS]; 79 | } cfg; /* config block */ 80 | 81 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 82 | Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); 83 | 84 | /* compute the initial chaining values ctx->X[], based on key */ 85 | if (keyBytes == 0) /* is there a key? */ 86 | { 87 | memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ 88 | } 89 | else /* here to pre-process a key */ 90 | { 91 | Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); 92 | /* do a mini-Init right here */ 93 | ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ 94 | Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ 95 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ 96 | Skein_256_Update(ctx,key,keyBytes); /* hash the key */ 97 | Skein_256_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ 98 | memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ 99 | #if SKEIN_NEED_SWAP 100 | { 101 | uint_t i; 102 | for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); 104 | } 105 | #endif 106 | } 107 | /* build/process the config block, type == CONFIG (could be precomputed for each key) */ 108 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 109 | Skein_Start_New_Type(ctx,CFG_FINAL); 110 | 111 | memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ 112 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); 113 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 114 | cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ 115 | 116 | Skein_Show_Key(256,&ctx->h,key,keyBytes); 117 | 118 | /* compute the initial chaining values from config block */ 119 | Skein_256_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 120 | 121 | /* The chaining vars ctx->X are now initialized */ 122 | /* Set up to process the data message portion of the hash (default) */ 123 | ctx->h.bCnt = 0; /* buffer b[] starts out empty */ 124 | Skein_Start_New_Type(ctx,MSG); 125 | 126 | return SKEIN_SUCCESS; 127 | } 128 | 129 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 130 | /* process the input bytes */ 131 | int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) 132 | { 133 | size_t n; 134 | 135 | Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 136 | 137 | /* process full blocks, if any */ 138 | if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) 139 | { 140 | if (ctx->h.bCnt) /* finish up any buffered message data */ 141 | { 142 | n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ 143 | if (n) 144 | { 145 | Skein_assert(n < msgByteCnt); /* check on our logic here */ 146 | memcpy(&ctx->b[ctx->h.bCnt],msg,n); 147 | msgByteCnt -= n; 148 | msg += n; 149 | ctx->h.bCnt += n; 150 | } 151 | Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES); 152 | Skein_256_Process_Block(ctx,ctx->b,1,SKEIN_256_BLOCK_BYTES); 153 | ctx->h.bCnt = 0; 154 | } 155 | /* now process any remaining full blocks, directly from input message data */ 156 | if (msgByteCnt > SKEIN_256_BLOCK_BYTES) 157 | { 158 | n = (msgByteCnt-1) / SKEIN_256_BLOCK_BYTES; /* number of full blocks to process */ 159 | Skein_256_Process_Block(ctx,msg,n,SKEIN_256_BLOCK_BYTES); 160 | msgByteCnt -= n * SKEIN_256_BLOCK_BYTES; 161 | msg += n * SKEIN_256_BLOCK_BYTES; 162 | } 163 | Skein_assert(ctx->h.bCnt == 0); 164 | } 165 | 166 | /* copy any remaining source message data bytes into b[] */ 167 | if (msgByteCnt) 168 | { 169 | Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES); 170 | memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); 171 | ctx->h.bCnt += msgByteCnt; 172 | } 173 | 174 | return SKEIN_SUCCESS; 175 | } 176 | 177 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 178 | /* finalize the hash computation and output the result */ 179 | int Skein_256_Final(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) 180 | { 181 | size_t i,n,byteCnt; 182 | u64b_t X[SKEIN_256_STATE_WORDS]; 183 | Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 184 | 185 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 186 | if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ 187 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); 188 | 189 | Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 190 | 191 | /* now output the result */ 192 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 193 | 194 | /* run Threefish in "counter mode" to generate output */ 195 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 196 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 197 | for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) 198 | { 199 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 200 | Skein_Start_New_Type(ctx,OUT_FINAL); 201 | Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 202 | n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ 203 | if (n >= SKEIN_256_BLOCK_BYTES) 204 | n = SKEIN_256_BLOCK_BYTES; 205 | Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 206 | Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); 207 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 208 | } 209 | return SKEIN_SUCCESS; 210 | } 211 | 212 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 213 | size_t Skein_256_API_CodeSize(void) 214 | { 215 | return ((u08b_t *) Skein_256_API_CodeSize) - 216 | ((u08b_t *) Skein_256_Init); 217 | } 218 | #endif 219 | 220 | /*****************************************************************/ 221 | /* 512-bit Skein */ 222 | /*****************************************************************/ 223 | 224 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 225 | /* init the context for a straight hashing operation */ 226 | int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen) 227 | { 228 | union 229 | { 230 | u08b_t b[SKEIN_512_STATE_BYTES]; 231 | u64b_t w[SKEIN_512_STATE_WORDS]; 232 | } cfg; /* config block */ 233 | 234 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 235 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 236 | 237 | switch (hashBitLen) 238 | { /* use pre-computed values, where available */ 239 | #ifndef SKEIN_NO_PRECOMP 240 | case 512: memcpy(ctx->X,SKEIN_512_IV_512,sizeof(ctx->X)); break; 241 | case 384: memcpy(ctx->X,SKEIN_512_IV_384,sizeof(ctx->X)); break; 242 | case 256: memcpy(ctx->X,SKEIN_512_IV_256,sizeof(ctx->X)); break; 243 | case 224: memcpy(ctx->X,SKEIN_512_IV_224,sizeof(ctx->X)); break; 244 | #endif 245 | default: 246 | /* here if there is no precomputed IV value available */ 247 | /* build/process the config block, type == CONFIG (could be precomputed) */ 248 | Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ 249 | 250 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ 251 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 252 | cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); 253 | memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ 254 | 255 | /* compute the initial chaining values from config block */ 256 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ 257 | Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 258 | break; 259 | } 260 | 261 | /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ 262 | /* Set up to process the data message portion of the hash (default) */ 263 | Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ 264 | 265 | return SKEIN_SUCCESS; 266 | } 267 | 268 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 269 | /* init the context for a MAC and/or tree hash operation */ 270 | /* [identical to Skein_512_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ 271 | int Skein_512_InitExt(Skein_512_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) 272 | { 273 | union 274 | { 275 | u08b_t b[SKEIN_512_STATE_BYTES]; 276 | u64b_t w[SKEIN_512_STATE_WORDS]; 277 | } cfg; /* config block */ 278 | 279 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 280 | Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); 281 | 282 | /* compute the initial chaining values ctx->X[], based on key */ 283 | if (keyBytes == 0) /* is there a key? */ 284 | { 285 | memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ 286 | } 287 | else /* here to pre-process a key */ 288 | { 289 | Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); 290 | /* do a mini-Init right here */ 291 | ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ 292 | Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ 293 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ 294 | Skein_512_Update(ctx,key,keyBytes); /* hash the key */ 295 | Skein_512_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ 296 | memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ 297 | #if SKEIN_NEED_SWAP 298 | { 299 | uint_t i; 300 | for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); 302 | } 303 | #endif 304 | } 305 | /* build/process the config block, type == CONFIG (could be precomputed for each key) */ 306 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 307 | Skein_Start_New_Type(ctx,CFG_FINAL); 308 | 309 | memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ 310 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); 311 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 312 | cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ 313 | 314 | Skein_Show_Key(512,&ctx->h,key,keyBytes); 315 | 316 | /* compute the initial chaining values from config block */ 317 | Skein_512_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 318 | 319 | /* The chaining vars ctx->X are now initialized */ 320 | /* Set up to process the data message portion of the hash (default) */ 321 | ctx->h.bCnt = 0; /* buffer b[] starts out empty */ 322 | Skein_Start_New_Type(ctx,MSG); 323 | 324 | return SKEIN_SUCCESS; 325 | } 326 | 327 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 328 | /* process the input bytes */ 329 | int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) 330 | { 331 | size_t n; 332 | 333 | Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 334 | 335 | /* process full blocks, if any */ 336 | if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) 337 | { 338 | if (ctx->h.bCnt) /* finish up any buffered message data */ 339 | { 340 | n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ 341 | if (n) 342 | { 343 | Skein_assert(n < msgByteCnt); /* check on our logic here */ 344 | memcpy(&ctx->b[ctx->h.bCnt],msg,n); 345 | msgByteCnt -= n; 346 | msg += n; 347 | ctx->h.bCnt += n; 348 | } 349 | Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES); 350 | Skein_512_Process_Block(ctx,ctx->b,1,SKEIN_512_BLOCK_BYTES); 351 | ctx->h.bCnt = 0; 352 | } 353 | /* now process any remaining full blocks, directly from input message data */ 354 | if (msgByteCnt > SKEIN_512_BLOCK_BYTES) 355 | { 356 | n = (msgByteCnt-1) / SKEIN_512_BLOCK_BYTES; /* number of full blocks to process */ 357 | Skein_512_Process_Block(ctx,msg,n,SKEIN_512_BLOCK_BYTES); 358 | msgByteCnt -= n * SKEIN_512_BLOCK_BYTES; 359 | msg += n * SKEIN_512_BLOCK_BYTES; 360 | } 361 | Skein_assert(ctx->h.bCnt == 0); 362 | } 363 | 364 | /* copy any remaining source message data bytes into b[] */ 365 | if (msgByteCnt) 366 | { 367 | Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES); 368 | memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); 369 | ctx->h.bCnt += msgByteCnt; 370 | } 371 | 372 | return SKEIN_SUCCESS; 373 | } 374 | 375 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 376 | /* finalize the hash computation and output the result */ 377 | int Skein_512_Final(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) 378 | { 379 | size_t i,n,byteCnt; 380 | u64b_t X[SKEIN_512_STATE_WORDS]; 381 | Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 382 | 383 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 384 | if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ 385 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); 386 | 387 | Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 388 | 389 | /* now output the result */ 390 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 391 | 392 | /* run Threefish in "counter mode" to generate output */ 393 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 394 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 395 | for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) 396 | { 397 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 398 | Skein_Start_New_Type(ctx,OUT_FINAL); 399 | Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 400 | n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ 401 | if (n >= SKEIN_512_BLOCK_BYTES) 402 | n = SKEIN_512_BLOCK_BYTES; 403 | Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 404 | Skein_Show_Final(512,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); 405 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 406 | } 407 | return SKEIN_SUCCESS; 408 | } 409 | 410 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 411 | size_t Skein_512_API_CodeSize(void) 412 | { 413 | return ((u08b_t *) Skein_512_API_CodeSize) - 414 | ((u08b_t *) Skein_512_Init); 415 | } 416 | #endif 417 | 418 | /*****************************************************************/ 419 | /* 1024-bit Skein */ 420 | /*****************************************************************/ 421 | 422 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 423 | /* init the context for a straight hashing operation */ 424 | int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen) 425 | { 426 | union 427 | { 428 | u08b_t b[SKEIN1024_STATE_BYTES]; 429 | u64b_t w[SKEIN1024_STATE_WORDS]; 430 | } cfg; /* config block */ 431 | 432 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 433 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 434 | 435 | switch (hashBitLen) 436 | { /* use pre-computed values, where available */ 437 | #ifndef SKEIN_NO_PRECOMP 438 | case 512: memcpy(ctx->X,SKEIN1024_IV_512 ,sizeof(ctx->X)); break; 439 | case 384: memcpy(ctx->X,SKEIN1024_IV_384 ,sizeof(ctx->X)); break; 440 | case 1024: memcpy(ctx->X,SKEIN1024_IV_1024,sizeof(ctx->X)); break; 441 | #endif 442 | default: 443 | /* here if there is no precomputed IV value available */ 444 | /* build/process the config block, type == CONFIG (could be precomputed) */ 445 | Skein_Start_New_Type(ctx,CFG_FINAL); /* set tweaks: T0=0; T1=CFG | FINAL */ 446 | 447 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); /* set the schema, version */ 448 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 449 | cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL); 450 | memset(&cfg.w[3],0,sizeof(cfg) - 3*sizeof(cfg.w[0])); /* zero pad config block */ 451 | 452 | /* compute the initial chaining values from config block */ 453 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the chaining variables */ 454 | Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 455 | break; 456 | } 457 | 458 | /* The chaining vars ctx->X are now initialized for the given hashBitLen. */ 459 | /* Set up to process the data message portion of the hash (default) */ 460 | Skein_Start_New_Type(ctx,MSG); /* T0=0, T1= MSG type */ 461 | 462 | return SKEIN_SUCCESS; 463 | } 464 | 465 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 466 | /* init the context for a MAC and/or tree hash operation */ 467 | /* [identical to Skein1024_Init() when keyBytes == 0 && treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL] */ 468 | int Skein1024_InitExt(Skein1024_Ctxt_t *ctx,size_t hashBitLen,u64b_t treeInfo, const u08b_t *key, size_t keyBytes) 469 | { 470 | union 471 | { 472 | u08b_t b[SKEIN1024_STATE_BYTES]; 473 | u64b_t w[SKEIN1024_STATE_WORDS]; 474 | } cfg; /* config block */ 475 | 476 | Skein_Assert(hashBitLen > 0,SKEIN_BAD_HASHLEN); 477 | Skein_Assert(keyBytes == 0 || key != NULL,SKEIN_FAIL); 478 | 479 | /* compute the initial chaining values ctx->X[], based on key */ 480 | if (keyBytes == 0) /* is there a key? */ 481 | { 482 | memset(ctx->X,0,sizeof(ctx->X)); /* no key: use all zeroes as key for config block */ 483 | } 484 | else /* here to pre-process a key */ 485 | { 486 | Skein_assert(sizeof(cfg.b) >= sizeof(ctx->X)); 487 | /* do a mini-Init right here */ 488 | ctx->h.hashBitLen=8*sizeof(ctx->X); /* set output hash bit count = state size */ 489 | Skein_Start_New_Type(ctx,KEY); /* set tweaks: T0 = 0; T1 = KEY type */ 490 | memset(ctx->X,0,sizeof(ctx->X)); /* zero the initial chaining variables */ 491 | Skein1024_Update(ctx,key,keyBytes); /* hash the key */ 492 | Skein1024_Final_Pad(ctx,cfg.b); /* put result into cfg.b[] */ 493 | memcpy(ctx->X,cfg.b,sizeof(cfg.b)); /* copy over into ctx->X[] */ 494 | #if SKEIN_NEED_SWAP 495 | { 496 | uint_t i; 497 | for (i=0;iX[i] = Skein_Swap64(ctx->X[i]); 499 | } 500 | #endif 501 | } 502 | /* build/process the config block, type == CONFIG (could be precomputed for each key) */ 503 | ctx->h.hashBitLen = hashBitLen; /* output hash bit count */ 504 | Skein_Start_New_Type(ctx,CFG_FINAL); 505 | 506 | memset(&cfg.w,0,sizeof(cfg.w)); /* pre-pad cfg.w[] with zeroes */ 507 | cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER); 508 | cfg.w[1] = Skein_Swap64(hashBitLen); /* hash result length in bits */ 509 | cfg.w[2] = Skein_Swap64(treeInfo); /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */ 510 | 511 | Skein_Show_Key(1024,&ctx->h,key,keyBytes); 512 | 513 | /* compute the initial chaining values from config block */ 514 | Skein1024_Process_Block(ctx,cfg.b,1,SKEIN_CFG_STR_LEN); 515 | 516 | /* The chaining vars ctx->X are now initialized */ 517 | /* Set up to process the data message portion of the hash (default) */ 518 | ctx->h.bCnt = 0; /* buffer b[] starts out empty */ 519 | Skein_Start_New_Type(ctx,MSG); 520 | 521 | return SKEIN_SUCCESS; 522 | } 523 | 524 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 525 | /* process the input bytes */ 526 | int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt) 527 | { 528 | size_t n; 529 | 530 | Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 531 | 532 | /* process full blocks, if any */ 533 | if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) 534 | { 535 | if (ctx->h.bCnt) /* finish up any buffered message data */ 536 | { 537 | n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt; /* # bytes free in buffer b[] */ 538 | if (n) 539 | { 540 | Skein_assert(n < msgByteCnt); /* check on our logic here */ 541 | memcpy(&ctx->b[ctx->h.bCnt],msg,n); 542 | msgByteCnt -= n; 543 | msg += n; 544 | ctx->h.bCnt += n; 545 | } 546 | Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES); 547 | Skein1024_Process_Block(ctx,ctx->b,1,SKEIN1024_BLOCK_BYTES); 548 | ctx->h.bCnt = 0; 549 | } 550 | /* now process any remaining full blocks, directly from input message data */ 551 | if (msgByteCnt > SKEIN1024_BLOCK_BYTES) 552 | { 553 | n = (msgByteCnt-1) / SKEIN1024_BLOCK_BYTES; /* number of full blocks to process */ 554 | Skein1024_Process_Block(ctx,msg,n,SKEIN1024_BLOCK_BYTES); 555 | msgByteCnt -= n * SKEIN1024_BLOCK_BYTES; 556 | msg += n * SKEIN1024_BLOCK_BYTES; 557 | } 558 | Skein_assert(ctx->h.bCnt == 0); 559 | } 560 | 561 | /* copy any remaining source message data bytes into b[] */ 562 | if (msgByteCnt) 563 | { 564 | Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES); 565 | memcpy(&ctx->b[ctx->h.bCnt],msg,msgByteCnt); 566 | ctx->h.bCnt += msgByteCnt; 567 | } 568 | 569 | return SKEIN_SUCCESS; 570 | } 571 | 572 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 573 | /* finalize the hash computation and output the result */ 574 | int Skein1024_Final(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) 575 | { 576 | size_t i,n,byteCnt; 577 | u64b_t X[SKEIN1024_STATE_WORDS]; 578 | Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 579 | 580 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 581 | if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ 582 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); 583 | 584 | Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 585 | 586 | /* now output the result */ 587 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 588 | 589 | /* run Threefish in "counter mode" to generate output */ 590 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 591 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 592 | for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) 593 | { 594 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 595 | Skein_Start_New_Type(ctx,OUT_FINAL); 596 | Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 597 | n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ 598 | if (n >= SKEIN1024_BLOCK_BYTES) 599 | n = SKEIN1024_BLOCK_BYTES; 600 | Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 601 | Skein_Show_Final(1024,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); 602 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 603 | } 604 | return SKEIN_SUCCESS; 605 | } 606 | 607 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 608 | size_t Skein1024_API_CodeSize(void) 609 | { 610 | return ((u08b_t *) Skein1024_API_CodeSize) - 611 | ((u08b_t *) Skein1024_Init); 612 | } 613 | #endif 614 | 615 | /**************** Functions to support MAC/tree hashing ***************/ 616 | /* (this code is identical for Optimized and Reference versions) */ 617 | 618 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 619 | /* finalize the hash computation and output the block, no OUTPUT stage */ 620 | int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) 621 | { 622 | Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 623 | 624 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 625 | if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES) /* zero pad b[] if necessary */ 626 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN_256_BLOCK_BYTES - ctx->h.bCnt); 627 | Skein_256_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 628 | 629 | Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_256_BLOCK_BYTES); /* "output" the state bytes */ 630 | 631 | return SKEIN_SUCCESS; 632 | } 633 | 634 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 635 | /* finalize the hash computation and output the block, no OUTPUT stage */ 636 | int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) 637 | { 638 | Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 639 | 640 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 641 | if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES) /* zero pad b[] if necessary */ 642 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN_512_BLOCK_BYTES - ctx->h.bCnt); 643 | Skein_512_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 644 | 645 | Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN_512_BLOCK_BYTES); /* "output" the state bytes */ 646 | 647 | return SKEIN_SUCCESS; 648 | } 649 | 650 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 651 | /* finalize the hash computation and output the block, no OUTPUT stage */ 652 | int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) 653 | { 654 | Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 655 | 656 | ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL; /* tag as the final block */ 657 | if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES) /* zero pad b[] if necessary */ 658 | memset(&ctx->b[ctx->h.bCnt],0,SKEIN1024_BLOCK_BYTES - ctx->h.bCnt); 659 | Skein1024_Process_Block(ctx,ctx->b,1,ctx->h.bCnt); /* process the final block */ 660 | 661 | Skein_Put64_LSB_First(hashVal,ctx->X,SKEIN1024_BLOCK_BYTES); /* "output" the state bytes */ 662 | 663 | return SKEIN_SUCCESS; 664 | } 665 | 666 | #if SKEIN_TREE_HASH 667 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 668 | /* just do the OUTPUT stage */ 669 | int Skein_256_Output(Skein_256_Ctxt_t *ctx, u08b_t *hashVal) 670 | { 671 | size_t i,n,byteCnt; 672 | u64b_t X[SKEIN_256_STATE_WORDS]; 673 | Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 674 | 675 | /* now output the result */ 676 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 677 | 678 | /* run Threefish in "counter mode" to generate output */ 679 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 680 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 681 | for (i=0;i*SKEIN_256_BLOCK_BYTES < byteCnt;i++) 682 | { 683 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 684 | Skein_Start_New_Type(ctx,OUT_FINAL); 685 | Skein_256_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 686 | n = byteCnt - i*SKEIN_256_BLOCK_BYTES; /* number of output bytes left to go */ 687 | if (n >= SKEIN_256_BLOCK_BYTES) 688 | n = SKEIN_256_BLOCK_BYTES; 689 | Skein_Put64_LSB_First(hashVal+i*SKEIN_256_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 690 | Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_256_BLOCK_BYTES); 691 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 692 | } 693 | return SKEIN_SUCCESS; 694 | } 695 | 696 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 697 | /* just do the OUTPUT stage */ 698 | int Skein_512_Output(Skein_512_Ctxt_t *ctx, u08b_t *hashVal) 699 | { 700 | size_t i,n,byteCnt; 701 | u64b_t X[SKEIN_512_STATE_WORDS]; 702 | Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 703 | 704 | /* now output the result */ 705 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 706 | 707 | /* run Threefish in "counter mode" to generate output */ 708 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 709 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 710 | for (i=0;i*SKEIN_512_BLOCK_BYTES < byteCnt;i++) 711 | { 712 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 713 | Skein_Start_New_Type(ctx,OUT_FINAL); 714 | Skein_512_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 715 | n = byteCnt - i*SKEIN_512_BLOCK_BYTES; /* number of output bytes left to go */ 716 | if (n >= SKEIN_512_BLOCK_BYTES) 717 | n = SKEIN_512_BLOCK_BYTES; 718 | Skein_Put64_LSB_First(hashVal+i*SKEIN_512_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 719 | Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN_512_BLOCK_BYTES); 720 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 721 | } 722 | return SKEIN_SUCCESS; 723 | } 724 | 725 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 726 | /* just do the OUTPUT stage */ 727 | int Skein1024_Output(Skein1024_Ctxt_t *ctx, u08b_t *hashVal) 728 | { 729 | size_t i,n,byteCnt; 730 | u64b_t X[SKEIN1024_STATE_WORDS]; 731 | Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES,SKEIN_FAIL); /* catch uninitialized context */ 732 | 733 | /* now output the result */ 734 | byteCnt = (ctx->h.hashBitLen + 7) >> 3; /* total number of output bytes */ 735 | 736 | /* run Threefish in "counter mode" to generate output */ 737 | memset(ctx->b,0,sizeof(ctx->b)); /* zero out b[], so it can hold the counter */ 738 | memcpy(X,ctx->X,sizeof(X)); /* keep a local copy of counter mode "key" */ 739 | for (i=0;i*SKEIN1024_BLOCK_BYTES < byteCnt;i++) 740 | { 741 | ((u64b_t *)ctx->b)[0]= Skein_Swap64((u64b_t) i); /* build the counter block */ 742 | Skein_Start_New_Type(ctx,OUT_FINAL); 743 | Skein1024_Process_Block(ctx,ctx->b,1,sizeof(u64b_t)); /* run "counter mode" */ 744 | n = byteCnt - i*SKEIN1024_BLOCK_BYTES; /* number of output bytes left to go */ 745 | if (n >= SKEIN1024_BLOCK_BYTES) 746 | n = SKEIN1024_BLOCK_BYTES; 747 | Skein_Put64_LSB_First(hashVal+i*SKEIN1024_BLOCK_BYTES,ctx->X,n); /* "output" the ctr mode bytes */ 748 | Skein_Show_Final(256,&ctx->h,n,hashVal+i*SKEIN1024_BLOCK_BYTES); 749 | memcpy(ctx->X,X,sizeof(X)); /* restore the counter mode key for next time */ 750 | } 751 | return SKEIN_SUCCESS; 752 | } 753 | #endif 754 | -------------------------------------------------------------------------------- /c_src/skein.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKEIN_H_ 2 | #define _SKEIN_H_ 1 3 | /************************************************************************** 4 | ** 5 | ** Interface declarations and internal definitions for Skein hashing. 6 | ** 7 | ** Source code author: Doug Whiting, 2008. 8 | ** 9 | ** This algorithm and source code is released to the public domain. 10 | ** 11 | *************************************************************************** 12 | ** 13 | ** The following compile-time switches may be defined to control some 14 | ** tradeoffs between speed, code size, error checking, and security. 15 | ** 16 | ** The "default" note explains what happens when the switch is not defined. 17 | ** 18 | ** SKEIN_DEBUG -- make callouts from inside Skein code 19 | ** to examine/display intermediate values. 20 | ** [default: no callouts (no overhead)] 21 | ** 22 | ** SKEIN_ERR_CHECK -- how error checking is handled inside Skein 23 | ** code. If not defined, most error checking 24 | ** is disabled (for performance). Otherwise, 25 | ** the switch value is interpreted as: 26 | ** 0: use assert() to flag errors 27 | ** 1: return SKEIN_FAIL to flag errors 28 | ** 29 | ***************************************************************************/ 30 | 31 | #include /* get size_t definition */ 32 | #include "skein_port.h" /* get platform-specific definitions */ 33 | 34 | enum 35 | { 36 | SKEIN_SUCCESS = 0, /* return codes from Skein calls */ 37 | SKEIN_FAIL = 1, 38 | SKEIN_BAD_HASHLEN = 2 39 | }; 40 | 41 | #define SKEIN_MODIFIER_WORDS ( 2) /* number of modifier (tweak) words */ 42 | 43 | #define SKEIN_256_STATE_WORDS ( 4) 44 | #define SKEIN_512_STATE_WORDS ( 8) 45 | #define SKEIN1024_STATE_WORDS (16) 46 | #define SKEIN_MAX_STATE_WORDS (16) 47 | 48 | #define SKEIN_256_STATE_BYTES ( 8*SKEIN_256_STATE_WORDS) 49 | #define SKEIN_512_STATE_BYTES ( 8*SKEIN_512_STATE_WORDS) 50 | #define SKEIN1024_STATE_BYTES ( 8*SKEIN1024_STATE_WORDS) 51 | 52 | #define SKEIN_256_STATE_BITS (64*SKEIN_256_STATE_WORDS) 53 | #define SKEIN_512_STATE_BITS (64*SKEIN_512_STATE_WORDS) 54 | #define SKEIN1024_STATE_BITS (64*SKEIN1024_STATE_WORDS) 55 | 56 | #define SKEIN_256_BLOCK_BYTES ( 8*SKEIN_256_STATE_WORDS) 57 | #define SKEIN_512_BLOCK_BYTES ( 8*SKEIN_512_STATE_WORDS) 58 | #define SKEIN1024_BLOCK_BYTES ( 8*SKEIN1024_STATE_WORDS) 59 | 60 | typedef struct 61 | { 62 | size_t hashBitLen; /* size of hash result, in bits */ 63 | size_t bCnt; /* current byte count in buffer b[] */ 64 | u64b_t T[SKEIN_MODIFIER_WORDS]; /* tweak words: T[0]=byte cnt, T[1]=flags */ 65 | } Skein_Ctxt_Hdr_t; 66 | 67 | typedef struct /* 256-bit Skein hash context structure */ 68 | { 69 | Skein_Ctxt_Hdr_t h; /* common header context variables */ 70 | u64b_t X[SKEIN_256_STATE_WORDS]; /* chaining variables */ 71 | u08b_t b[SKEIN_256_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ 72 | } Skein_256_Ctxt_t; 73 | 74 | typedef struct /* 512-bit Skein hash context structure */ 75 | { 76 | Skein_Ctxt_Hdr_t h; /* common header context variables */ 77 | u64b_t X[SKEIN_512_STATE_WORDS]; /* chaining variables */ 78 | u08b_t b[SKEIN_512_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ 79 | } Skein_512_Ctxt_t; 80 | 81 | typedef struct /* 1024-bit Skein hash context structure */ 82 | { 83 | Skein_Ctxt_Hdr_t h; /* common header context variables */ 84 | u64b_t X[SKEIN1024_STATE_WORDS]; /* chaining variables */ 85 | u08b_t b[SKEIN1024_BLOCK_BYTES]; /* partial block buffer (8-byte aligned) */ 86 | } Skein1024_Ctxt_t; 87 | 88 | /* Skein APIs for (incremental) "straight hashing" */ 89 | int Skein_256_Init (Skein_256_Ctxt_t *ctx, size_t hashBitLen); 90 | int Skein_512_Init (Skein_512_Ctxt_t *ctx, size_t hashBitLen); 91 | int Skein1024_Init (Skein1024_Ctxt_t *ctx, size_t hashBitLen); 92 | 93 | int Skein_256_Update(Skein_256_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); 94 | int Skein_512_Update(Skein_512_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); 95 | int Skein1024_Update(Skein1024_Ctxt_t *ctx, const u08b_t *msg, size_t msgByteCnt); 96 | 97 | int Skein_256_Final (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); 98 | int Skein_512_Final (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); 99 | int Skein1024_Final (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); 100 | 101 | /* 102 | ** Skein APIs for "extended" initialization: MAC keys, tree hashing. 103 | ** After an InitExt() call, just use Update/Final calls as with Init(). 104 | ** 105 | ** Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes. 106 | ** When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL, 107 | ** the results of InitExt() are identical to calling Init(). 108 | ** The function Init() may be called once to "precompute" the IV for 109 | ** a given hashBitLen value, then by saving a copy of the context 110 | ** the IV computation may be avoided in later calls. 111 | ** Similarly, the function InitExt() may be called once per MAC key 112 | ** to precompute the MAC IV, then a copy of the context saved and 113 | ** reused for each new MAC computation. 114 | **/ 115 | int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); 116 | int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); 117 | int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, u64b_t treeInfo, const u08b_t *key, size_t keyBytes); 118 | 119 | /* 120 | ** Skein APIs for MAC and tree hash: 121 | ** Final_Pad: pad, do final block, but no OUTPUT type 122 | ** Output: do just the output stage 123 | */ 124 | int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, u08b_t * hashVal); 125 | int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, u08b_t * hashVal); 126 | int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, u08b_t * hashVal); 127 | 128 | #ifndef SKEIN_TREE_HASH 129 | #define SKEIN_TREE_HASH (1) 130 | #endif 131 | #if SKEIN_TREE_HASH 132 | int Skein_256_Output (Skein_256_Ctxt_t *ctx, u08b_t * hashVal); 133 | int Skein_512_Output (Skein_512_Ctxt_t *ctx, u08b_t * hashVal); 134 | int Skein1024_Output (Skein1024_Ctxt_t *ctx, u08b_t * hashVal); 135 | #endif 136 | 137 | /***************************************************************** 138 | ** "Internal" Skein definitions 139 | ** -- not needed for sequential hashing API, but will be 140 | ** helpful for other uses of Skein (e.g., tree hash mode). 141 | ** -- included here so that they can be shared between 142 | ** reference and optimized code. 143 | ******************************************************************/ 144 | 145 | /* tweak word T[1]: bit field starting positions */ 146 | #define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */ 147 | 148 | #define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */ 149 | #define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */ 150 | #define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */ 151 | #define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */ 152 | #define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */ 153 | 154 | /* tweak word T[1]: flag bit definition(s) */ 155 | #define SKEIN_T1_FLAG_FIRST (((u64b_t) 1 ) << SKEIN_T1_POS_FIRST) 156 | #define SKEIN_T1_FLAG_FINAL (((u64b_t) 1 ) << SKEIN_T1_POS_FINAL) 157 | #define SKEIN_T1_FLAG_BIT_PAD (((u64b_t) 1 ) << SKEIN_T1_POS_BIT_PAD) 158 | 159 | /* tweak word T[1]: tree level bit field mask */ 160 | #define SKEIN_T1_TREE_LVL_MASK (((u64b_t)0x7F) << SKEIN_T1_POS_TREE_LVL) 161 | #define SKEIN_T1_TREE_LEVEL(n) (((u64b_t) (n)) << SKEIN_T1_POS_TREE_LVL) 162 | 163 | /* tweak word T[1]: block type field */ 164 | #define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */ 165 | #define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */ 166 | #define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */ 167 | #define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */ 168 | #define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */ 169 | #define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */ 170 | #define SKEIN_BLK_TYPE_MSG (48) /* message processing */ 171 | #define SKEIN_BLK_TYPE_OUT (63) /* output stage */ 172 | #define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */ 173 | 174 | #define SKEIN_T1_BLK_TYPE(T) (((u64b_t) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE) 175 | #define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */ 176 | #define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */ 177 | #define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */ 178 | #define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */ 179 | #define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */ 180 | #define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */ 181 | #define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */ 182 | #define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */ 183 | #define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */ 184 | 185 | #define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL) 186 | #define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL) 187 | 188 | #define SKEIN_VERSION (1) 189 | 190 | #ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */ 191 | #define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/ 192 | #endif 193 | 194 | #define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64b_t) (hi32)) << 32)) 195 | #define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE) 196 | #define SKEIN_KS_PARITY SKEIN_MK_64(0x55555555,0x55555555) 197 | 198 | #define SKEIN_CFG_STR_LEN (4*8) 199 | 200 | /* bit field definitions in config block treeInfo word */ 201 | #define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0) 202 | #define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8) 203 | #define SKEIN_CFG_TREE_MAX_LEVEL_POS (16) 204 | 205 | #define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS) 206 | #define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS) 207 | #define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64b_t) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS) 208 | 209 | #define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl) \ 210 | ( (((u64b_t)(leaf )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \ 211 | (((u64b_t)(node )) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \ 212 | (((u64b_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) ) 213 | 214 | #define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0) /* use as treeInfo in InitExt() call for sequential processing */ 215 | 216 | /* 217 | ** Skein macros for getting/setting tweak words, etc. 218 | ** These are useful for partial input bytes, hash tree init/update, etc. 219 | **/ 220 | #define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->h.T[TWK_NUM]) 221 | #define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->h.T[TWK_NUM] = (tVal);} 222 | 223 | #define Skein_Get_T0(ctxPtr) Skein_Get_Tweak(ctxPtr,0) 224 | #define Skein_Get_T1(ctxPtr) Skein_Get_Tweak(ctxPtr,1) 225 | #define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0) 226 | #define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1) 227 | 228 | /* set both tweak words at once */ 229 | #define Skein_Set_T0_T1(ctxPtr,T0,T1) \ 230 | { \ 231 | Skein_Set_T0(ctxPtr,(T0)); \ 232 | Skein_Set_T1(ctxPtr,(T1)); \ 233 | } 234 | 235 | #define Skein_Set_Type(ctxPtr,BLK_TYPE) \ 236 | Skein_Set_T1(ctxPtr,SKEIN_T1_BLK_TYPE_##BLK_TYPE) 237 | 238 | /* set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0; */ 239 | #define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \ 240 | { Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | SKEIN_T1_BLK_TYPE_##BLK_TYPE); (ctxPtr)->h.bCnt=0; } 241 | 242 | #define Skein_Clear_First_Flag(hdr) { (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST; } 243 | #define Skein_Set_Bit_Pad_Flag(hdr) { (hdr).T[1] |= SKEIN_T1_FLAG_BIT_PAD; } 244 | 245 | #define Skein_Set_Tree_Level(hdr,height) { (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);} 246 | 247 | /***************************************************************** 248 | ** "Internal" Skein definitions for debugging and error checking 249 | ******************************************************************/ 250 | #ifdef SKEIN_DEBUG /* examine/display intermediate values? */ 251 | #include "skein_debug.h" 252 | #else /* default is no callouts */ 253 | #define Skein_Show_Block(bits,ctx,X,blkPtr,wPtr,ksEvenPtr,ksOddPtr) 254 | #define Skein_Show_Round(bits,ctx,r,X) 255 | #define Skein_Show_R_Ptr(bits,ctx,r,X_ptr) 256 | #define Skein_Show_Final(bits,ctx,cnt,outPtr) 257 | #define Skein_Show_Key(bits,ctx,key,keyBytes) 258 | #endif 259 | 260 | #ifndef SKEIN_ERR_CHECK /* run-time checks (e.g., bad params, uninitialized context)? */ 261 | #define Skein_Assert(x,retCode)/* default: ignore all Asserts, for performance */ 262 | #define Skein_assert(x) 263 | #elif defined(SKEIN_ASSERT) 264 | #include 265 | #define Skein_Assert(x,retCode) assert(x) 266 | #define Skein_assert(x) assert(x) 267 | #else 268 | #include 269 | #define Skein_Assert(x,retCode) { if (!(x)) return retCode; } /* caller error */ 270 | #define Skein_assert(x) assert(x) /* internal error */ 271 | #endif 272 | 273 | /***************************************************************** 274 | ** Skein block function constants (shared across Ref and Opt code) 275 | ******************************************************************/ 276 | enum 277 | { 278 | /* Skein_256 round rotation constants */ 279 | R_256_0_0=14, R_256_0_1=16, 280 | R_256_1_0=52, R_256_1_1=57, 281 | R_256_2_0=23, R_256_2_1=40, 282 | R_256_3_0= 5, R_256_3_1=37, 283 | R_256_4_0=25, R_256_4_1=33, 284 | R_256_5_0=46, R_256_5_1=12, 285 | R_256_6_0=58, R_256_6_1=22, 286 | R_256_7_0=32, R_256_7_1=32, 287 | 288 | /* Skein_512 round rotation constants */ 289 | R_512_0_0=46, R_512_0_1=36, R_512_0_2=19, R_512_0_3=37, 290 | R_512_1_0=33, R_512_1_1=27, R_512_1_2=14, R_512_1_3=42, 291 | R_512_2_0=17, R_512_2_1=49, R_512_2_2=36, R_512_2_3=39, 292 | R_512_3_0=44, R_512_3_1= 9, R_512_3_2=54, R_512_3_3=56, 293 | R_512_4_0=39, R_512_4_1=30, R_512_4_2=34, R_512_4_3=24, 294 | R_512_5_0=13, R_512_5_1=50, R_512_5_2=10, R_512_5_3=17, 295 | R_512_6_0=25, R_512_6_1=29, R_512_6_2=39, R_512_6_3=43, 296 | R_512_7_0= 8, R_512_7_1=35, R_512_7_2=56, R_512_7_3=22, 297 | 298 | /* Skein1024 round rotation constants */ 299 | 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, 300 | 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, 301 | 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, 302 | 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, 303 | 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, 304 | 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, 305 | 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, 306 | 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 307 | }; 308 | 309 | #ifndef SKEIN_ROUNDS 310 | #define SKEIN_256_ROUNDS_TOTAL (72) /* number of rounds for the different block sizes */ 311 | #define SKEIN_512_ROUNDS_TOTAL (72) 312 | #define SKEIN1024_ROUNDS_TOTAL (80) 313 | #else /* allow command-line define in range 8*(5..14) */ 314 | #define SKEIN_256_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/100) + 5) % 10) + 5)) 315 | #define SKEIN_512_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS/ 10) + 5) % 10) + 5)) 316 | #define SKEIN1024_ROUNDS_TOTAL (8*((((SKEIN_ROUNDS ) + 5) % 10) + 5)) 317 | #endif 318 | 319 | #endif /* ifndef _SKEIN_H_ */ 320 | -------------------------------------------------------------------------------- /c_src/skein_api.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | ** 3 | ** Implementation of the AHS API using the Skein hash function. 4 | ** 5 | ** Source code author: Doug Whiting, 2008. 6 | ** 7 | ** This algorithm and source code is released to the public domain. 8 | ** 9 | ************************************************************************/ 10 | 11 | #include /* get the memcpy/memset functions */ 12 | #include "skein.h" /* get the Skein API definitions */ 13 | #include "skein_api.h"/* get the AHS API definitions */ 14 | 15 | /******************************************************************/ 16 | /* AHS API code */ 17 | /******************************************************************/ 18 | 19 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 20 | /* select the context size and init the context */ 21 | HashReturn Init(hashState *state, int hashbitlen) 22 | { 23 | if (hashbitlen <= SKEIN_256_NIST_MAX_HASHBITS) 24 | { 25 | Skein_Assert(hashbitlen > 0,BAD_HASHLEN); 26 | state->statebits = 64*SKEIN_256_STATE_WORDS; 27 | return Skein_256_Init(&state->u.ctx_256,(size_t) hashbitlen); 28 | } 29 | if (hashbitlen <= SKEIN_512_NIST_MAX_HASHBITS) 30 | { 31 | state->statebits = 64*SKEIN_512_STATE_WORDS; 32 | return Skein_512_Init(&state->u.ctx_512,(size_t) hashbitlen); 33 | } 34 | else 35 | { 36 | state->statebits = 64*SKEIN1024_STATE_WORDS; 37 | return Skein1024_Init(&state->u.ctx1024,(size_t) hashbitlen); 38 | } 39 | } 40 | 41 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 42 | /* process data to be hashed */ 43 | HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) 44 | { 45 | /* only the final Update() call is allowed do partial bytes, else assert an error */ 46 | Skein_Assert((state->u.h.T[1] & SKEIN_T1_FLAG_BIT_PAD) == 0 || databitlen == 0, FAIL); 47 | 48 | Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL); 49 | if ((databitlen & 7) == 0) /* partial bytes? */ 50 | { 51 | switch ((state->statebits >> 8) & 3) 52 | { 53 | case 2: return Skein_512_Update(&state->u.ctx_512,data,databitlen >> 3); 54 | case 1: return Skein_256_Update(&state->u.ctx_256,data,databitlen >> 3); 55 | case 0: return Skein1024_Update(&state->u.ctx1024,data,databitlen >> 3); 56 | default: return FAIL; 57 | } 58 | } 59 | else 60 | { /* handle partial final byte */ 61 | size_t bCnt = (databitlen >> 3) + 1; /* number of bytes to handle (nonzero here!) */ 62 | u08b_t b,mask; 63 | 64 | mask = (u08b_t) (1u << (7 - (databitlen & 7))); /* partial byte bit mask */ 65 | b = (u08b_t) ((data[bCnt-1] & (0-mask)) | mask); /* apply bit padding on final byte */ 66 | 67 | switch ((state->statebits >> 8) & 3) 68 | { 69 | case 2: Skein_512_Update(&state->u.ctx_512,data,bCnt-1); /* process all but the final byte */ 70 | Skein_512_Update(&state->u.ctx_512,&b , 1 ); /* process the (masked) partial byte */ 71 | break; 72 | case 1: Skein_256_Update(&state->u.ctx_256,data,bCnt-1); /* process all but the final byte */ 73 | Skein_256_Update(&state->u.ctx_256,&b , 1 ); /* process the (masked) partial byte */ 74 | break; 75 | case 0: Skein1024_Update(&state->u.ctx1024,data,bCnt-1); /* process all but the final byte */ 76 | Skein1024_Update(&state->u.ctx1024,&b , 1 ); /* process the (masked) partial byte */ 77 | break; 78 | default: return FAIL; 79 | } 80 | Skein_Set_Bit_Pad_Flag(state->u.h); /* set tweak flag for the final call */ 81 | 82 | return SUCCESS; 83 | } 84 | } 85 | 86 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 87 | /* finalize hash computation and output the result (hashbitlen bits) */ 88 | HashReturn Final(hashState *state, BitSequence *hashval) 89 | { 90 | Skein_Assert(state->statebits % 256 == 0 && (state->statebits-256) < 1024,FAIL); 91 | switch ((state->statebits >> 8) & 3) 92 | { 93 | case 2: return Skein_512_Final(&state->u.ctx_512,hashval); 94 | case 1: return Skein_256_Final(&state->u.ctx_256,hashval); 95 | case 0: return Skein1024_Final(&state->u.ctx1024,hashval); 96 | default: return FAIL; 97 | } 98 | } 99 | 100 | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ 101 | /* all-in-one hash function */ 102 | HashReturn Hash(int hashbitlen, const BitSequence *data, /* all-in-one call */ 103 | DataLength databitlen, BitSequence *hashval) 104 | { 105 | hashState state; 106 | HashReturn r = Init(&state,hashbitlen); 107 | if (r == SUCCESS) 108 | { /* these calls do not fail when called properly */ 109 | r = Update(&state,data,databitlen); 110 | Final(&state,hashval); 111 | } 112 | return r; 113 | } 114 | -------------------------------------------------------------------------------- /c_src/skein_api.h: -------------------------------------------------------------------------------- 1 | #ifndef _AHS_API_H_ 2 | #define _AHS_API_H_ 3 | 4 | /*********************************************************************** 5 | ** 6 | ** Interface declarations of the AHS API using the Skein hash function. 7 | ** 8 | ** Source code author: Doug Whiting, 2008. 9 | ** 10 | ** This algorithm and source code is released to the public domain. 11 | ** 12 | ************************************************************************/ 13 | 14 | #include "skein.h" 15 | 16 | typedef enum 17 | { 18 | SUCCESS = SKEIN_SUCCESS, 19 | FAIL = SKEIN_FAIL, 20 | BAD_HASHLEN = SKEIN_BAD_HASHLEN 21 | } 22 | HashReturn; 23 | 24 | typedef size_t DataLength; /* bit count type */ 25 | typedef u08b_t BitSequence; /* bit stream type */ 26 | 27 | typedef struct 28 | { 29 | uint_t statebits; /* 256, 512, or 1024 */ 30 | union 31 | { 32 | Skein_Ctxt_Hdr_t h; /* common header "overlay" */ 33 | Skein_256_Ctxt_t ctx_256; 34 | Skein_512_Ctxt_t ctx_512; 35 | Skein1024_Ctxt_t ctx1024; 36 | } u; 37 | } 38 | hashState; 39 | 40 | /* "incremental" hashing API */ 41 | HashReturn Init (hashState *state, int hashbitlen); 42 | HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); 43 | HashReturn Final (hashState *state, BitSequence *hashval); 44 | 45 | /* "all-in-one" call */ 46 | HashReturn Hash (int hashbitlen, const BitSequence *data, 47 | DataLength databitlen, BitSequence *hashval); 48 | 49 | 50 | /* 51 | ** Re-define the compile-time constants below to change the selection 52 | ** of the Skein state size in the Init() function in SHA3api_ref.c. 53 | ** 54 | ** That is, the NIST API does not allow for explicit selection of the 55 | ** Skein block size, so it must be done implicitly in the Init() function. 56 | ** The selection is controlled by these constants. 57 | */ 58 | #ifndef SKEIN_256_NIST_MAX_HASHBITS 59 | #define SKEIN_256_NIST_MAX_HASHBITS (256) 60 | #endif 61 | 62 | #ifndef SKEIN_512_NIST_MAX_HASHBITS 63 | #define SKEIN_512_NIST_MAX_HASHBITS (512) 64 | #endif 65 | 66 | #endif /* ifdef _AHS_API_H_ */ 67 | -------------------------------------------------------------------------------- /c_src/skein_block.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | ** 3 | ** Implementation of the Skein block functions. 4 | ** 5 | ** Source code author: Doug Whiting, 2008. 6 | ** 7 | ** This algorithm and source code is released to the public domain. 8 | ** 9 | ** Compile-time switches: 10 | ** 11 | ** SKEIN_USE_ASM -- set bits (256/512/1024) to select which 12 | ** versions use ASM code for block processing 13 | ** [default: use C for all block sizes] 14 | ** 15 | ************************************************************************/ 16 | 17 | #include 18 | #include "skein.h" 19 | 20 | #ifndef SKEIN_USE_ASM 21 | #define SKEIN_USE_ASM (0) /* default is all C code (no ASM) */ 22 | #endif 23 | 24 | #ifndef SKEIN_LOOP 25 | #define SKEIN_LOOP 001 /* default: unroll 256 and 512, but not 1024 */ 26 | #endif 27 | 28 | #define BLK_BITS (WCNT*64) /* some useful definitions for code here */ 29 | #define KW_TWK_BASE (0) 30 | #define KW_KEY_BASE (3) 31 | #define ks (kw + KW_KEY_BASE) 32 | #define ts (kw + KW_TWK_BASE) 33 | 34 | #ifdef SKEIN_DEBUG 35 | #define DebugSaveTweak(ctx) { ctx->h.T[0] = ts[0]; ctx->h.T[1] = ts[1]; } 36 | #else 37 | #define DebugSaveTweak(ctx) 38 | #endif 39 | 40 | /***************************** Skein_256 ******************************/ 41 | #if !(SKEIN_USE_ASM & 256) 42 | void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) 43 | { /* do it in C */ 44 | enum 45 | { 46 | WCNT = SKEIN_256_STATE_WORDS 47 | }; 48 | #undef RCNT 49 | #define RCNT (SKEIN_256_ROUNDS_TOTAL/8) 50 | 51 | #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ 52 | #define SKEIN_UNROLL_256 (((SKEIN_LOOP)/100)%10) 53 | #else 54 | #define SKEIN_UNROLL_256 (0) 55 | #endif 56 | 57 | #if SKEIN_UNROLL_256 58 | #if (RCNT % SKEIN_UNROLL_256) 59 | #error "Invalid SKEIN_UNROLL_256" /* sanity check on unroll count */ 60 | #endif 61 | size_t r; 62 | u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ 63 | #else 64 | u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ 65 | #endif 66 | u64b_t X0,X1,X2,X3; /* local copy of context vars, for speed */ 67 | u64b_t w [WCNT]; /* local copy of input block */ 68 | #ifdef SKEIN_DEBUG 69 | const u64b_t *Xptr[4]; /* use for debugging (help compiler put Xn in registers) */ 70 | Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; 71 | #endif 72 | Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ 73 | ts[0] = ctx->h.T[0]; 74 | ts[1] = ctx->h.T[1]; 75 | do { 76 | /* this implementation only supports 2**64 input bytes (no carry out here) */ 77 | ts[0] += byteCntAdd; /* update processed length */ 78 | 79 | /* precompute the key schedule for this block */ 80 | ks[0] = ctx->X[0]; 81 | ks[1] = ctx->X[1]; 82 | ks[2] = ctx->X[2]; 83 | ks[3] = ctx->X[3]; 84 | ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY; 85 | 86 | ts[2] = ts[0] ^ ts[1]; 87 | 88 | Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ 89 | DebugSaveTweak(ctx); 90 | Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); 91 | 92 | X0 = w[0] + ks[0]; /* do the first full key injection */ 93 | X1 = w[1] + ks[1] + ts[0]; 94 | X2 = w[2] + ks[2] + ts[1]; 95 | X3 = w[3] + ks[3]; 96 | 97 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); /* show starting state values */ 98 | 99 | blkPtr += SKEIN_256_BLOCK_BYTES; 100 | 101 | /* run the rounds */ 102 | 103 | #define Round256(p0,p1,p2,p3,ROT,rNum) \ 104 | X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ 105 | X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ 106 | 107 | #if SKEIN_UNROLL_256 == 0 108 | #define R256(p0,p1,p2,p3,ROT,rNum) /* fully unrolled */ \ 109 | Round256(p0,p1,p2,p3,ROT,rNum) \ 110 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); 111 | 112 | #define I256(R) \ 113 | X0 += ks[((R)+1) % 5]; /* inject the key schedule value */ \ 114 | X1 += ks[((R)+2) % 5] + ts[((R)+1) % 3]; \ 115 | X2 += ks[((R)+3) % 5] + ts[((R)+2) % 3]; \ 116 | X3 += ks[((R)+4) % 5] + (R)+1; \ 117 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 118 | #else /* looping version */ 119 | #define R256(p0,p1,p2,p3,ROT,rNum) \ 120 | Round256(p0,p1,p2,p3,ROT,rNum) \ 121 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); 122 | 123 | #define I256(R) \ 124 | X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ 125 | X1 += ks[r+(R)+1] + ts[r+(R)+0]; \ 126 | X2 += ks[r+(R)+2] + ts[r+(R)+1]; \ 127 | X3 += ks[r+(R)+3] + r+(R) ; \ 128 | ks[r + (R)+4 ] = ks[r+(R)-1]; /* rotate key schedule */\ 129 | ts[r + (R)+2 ] = ts[r+(R)-1]; \ 130 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 131 | 132 | for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_256) /* loop thru it */ 133 | #endif 134 | { 135 | #define R256_8_rounds(R) \ 136 | R256(0,1,2,3,R_256_0,8*(R) + 1); \ 137 | R256(0,3,2,1,R_256_1,8*(R) + 2); \ 138 | R256(0,1,2,3,R_256_2,8*(R) + 3); \ 139 | R256(0,3,2,1,R_256_3,8*(R) + 4); \ 140 | I256(2*(R)); \ 141 | R256(0,1,2,3,R_256_4,8*(R) + 5); \ 142 | R256(0,3,2,1,R_256_5,8*(R) + 6); \ 143 | R256(0,1,2,3,R_256_6,8*(R) + 7); \ 144 | R256(0,3,2,1,R_256_7,8*(R) + 8); \ 145 | I256(2*(R)+1); 146 | 147 | R256_8_rounds( 0); 148 | 149 | #define R256_Unroll_R(NN) ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_256 > (NN))) 150 | 151 | #if R256_Unroll_R( 1) 152 | R256_8_rounds( 1); 153 | #endif 154 | #if R256_Unroll_R( 2) 155 | R256_8_rounds( 2); 156 | #endif 157 | #if R256_Unroll_R( 3) 158 | R256_8_rounds( 3); 159 | #endif 160 | #if R256_Unroll_R( 4) 161 | R256_8_rounds( 4); 162 | #endif 163 | #if R256_Unroll_R( 5) 164 | R256_8_rounds( 5); 165 | #endif 166 | #if R256_Unroll_R( 6) 167 | R256_8_rounds( 6); 168 | #endif 169 | #if R256_Unroll_R( 7) 170 | R256_8_rounds( 7); 171 | #endif 172 | #if R256_Unroll_R( 8) 173 | R256_8_rounds( 8); 174 | #endif 175 | #if R256_Unroll_R( 9) 176 | R256_8_rounds( 9); 177 | #endif 178 | #if R256_Unroll_R(10) 179 | R256_8_rounds(10); 180 | #endif 181 | #if R256_Unroll_R(11) 182 | R256_8_rounds(11); 183 | #endif 184 | #if R256_Unroll_R(12) 185 | R256_8_rounds(12); 186 | #endif 187 | #if R256_Unroll_R(13) 188 | R256_8_rounds(13); 189 | #endif 190 | #if R256_Unroll_R(14) 191 | R256_8_rounds(14); 192 | #endif 193 | #if (SKEIN_UNROLL_256 > 14) 194 | #error "need more unrolling in Skein_256_Process_Block" 195 | #endif 196 | } 197 | /* do the final "feedforward" xor, update context chaining vars */ 198 | ctx->X[0] = X0 ^ w[0]; 199 | ctx->X[1] = X1 ^ w[1]; 200 | ctx->X[2] = X2 ^ w[2]; 201 | ctx->X[3] = X3 ^ w[3]; 202 | 203 | Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); 204 | 205 | ts[1] &= ~SKEIN_T1_FLAG_FIRST; 206 | } 207 | while (--blkCnt); 208 | ctx->h.T[0] = ts[0]; 209 | ctx->h.T[1] = ts[1]; 210 | } 211 | 212 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 213 | size_t Skein_256_Process_Block_CodeSize(void) 214 | { 215 | return ((u08b_t *) Skein_256_Process_Block_CodeSize) - 216 | ((u08b_t *) Skein_256_Process_Block); 217 | } 218 | uint_t Skein_256_Unroll_Cnt(void) 219 | { 220 | return SKEIN_UNROLL_256; 221 | } 222 | #endif 223 | #endif 224 | 225 | /***************************** Skein_512 ******************************/ 226 | #if !(SKEIN_USE_ASM & 512) 227 | void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) 228 | { /* do it in C */ 229 | enum 230 | { 231 | WCNT = SKEIN_512_STATE_WORDS 232 | }; 233 | #undef RCNT 234 | #define RCNT (SKEIN_512_ROUNDS_TOTAL/8) 235 | 236 | #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ 237 | #define SKEIN_UNROLL_512 (((SKEIN_LOOP)/10)%10) 238 | #else 239 | #define SKEIN_UNROLL_512 (0) 240 | #endif 241 | 242 | #if SKEIN_UNROLL_512 243 | #if (RCNT % SKEIN_UNROLL_512) 244 | #error "Invalid SKEIN_UNROLL_512" /* sanity check on unroll count */ 245 | #endif 246 | size_t r; 247 | u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ 248 | #else 249 | u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ 250 | #endif 251 | u64b_t X0,X1,X2,X3,X4,X5,X6,X7; /* local copy of vars, for speed */ 252 | u64b_t w [WCNT]; /* local copy of input block */ 253 | #ifdef SKEIN_DEBUG 254 | const u64b_t *Xptr[8]; /* use for debugging (help compiler put Xn in registers) */ 255 | Xptr[0] = &X0; Xptr[1] = &X1; Xptr[2] = &X2; Xptr[3] = &X3; 256 | Xptr[4] = &X4; Xptr[5] = &X5; Xptr[6] = &X6; Xptr[7] = &X7; 257 | #endif 258 | 259 | Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ 260 | ts[0] = ctx->h.T[0]; 261 | ts[1] = ctx->h.T[1]; 262 | do { 263 | /* this implementation only supports 2**64 input bytes (no carry out here) */ 264 | ts[0] += byteCntAdd; /* update processed length */ 265 | 266 | /* precompute the key schedule for this block */ 267 | ks[0] = ctx->X[0]; 268 | ks[1] = ctx->X[1]; 269 | ks[2] = ctx->X[2]; 270 | ks[3] = ctx->X[3]; 271 | ks[4] = ctx->X[4]; 272 | ks[5] = ctx->X[5]; 273 | ks[6] = ctx->X[6]; 274 | ks[7] = ctx->X[7]; 275 | ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ 276 | ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY; 277 | 278 | ts[2] = ts[0] ^ ts[1]; 279 | 280 | Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ 281 | DebugSaveTweak(ctx); 282 | Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); 283 | 284 | X0 = w[0] + ks[0]; /* do the first full key injection */ 285 | X1 = w[1] + ks[1]; 286 | X2 = w[2] + ks[2]; 287 | X3 = w[3] + ks[3]; 288 | X4 = w[4] + ks[4]; 289 | X5 = w[5] + ks[5] + ts[0]; 290 | X6 = w[6] + ks[6] + ts[1]; 291 | X7 = w[7] + ks[7]; 292 | 293 | blkPtr += SKEIN_512_BLOCK_BYTES; 294 | 295 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); 296 | /* run the rounds */ 297 | #define Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ 298 | X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ 299 | X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ 300 | X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ 301 | X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ 302 | 303 | #if SKEIN_UNROLL_512 == 0 304 | #define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) /* unrolled */ \ 305 | Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ 306 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rNum,Xptr); 307 | 308 | #define I512(R) \ 309 | X0 += ks[((R)+1) % 9]; /* inject the key schedule value */ \ 310 | X1 += ks[((R)+2) % 9]; \ 311 | X2 += ks[((R)+3) % 9]; \ 312 | X3 += ks[((R)+4) % 9]; \ 313 | X4 += ks[((R)+5) % 9]; \ 314 | X5 += ks[((R)+6) % 9] + ts[((R)+1) % 3]; \ 315 | X6 += ks[((R)+7) % 9] + ts[((R)+2) % 3]; \ 316 | X7 += ks[((R)+8) % 9] + (R)+1; \ 317 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 318 | #else /* looping version */ 319 | #define R512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ 320 | Round512(p0,p1,p2,p3,p4,p5,p6,p7,ROT,rNum) \ 321 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rNum,Xptr); 322 | 323 | #define I512(R) \ 324 | X0 += ks[r+(R)+0]; /* inject the key schedule value */ \ 325 | X1 += ks[r+(R)+1]; \ 326 | X2 += ks[r+(R)+2]; \ 327 | X3 += ks[r+(R)+3]; \ 328 | X4 += ks[r+(R)+4]; \ 329 | X5 += ks[r+(R)+5] + ts[r+(R)+0]; \ 330 | X6 += ks[r+(R)+6] + ts[r+(R)+1]; \ 331 | X7 += ks[r+(R)+7] + r+(R) ; \ 332 | ks[r + (R)+8] = ks[r+(R)-1]; /* rotate key schedule */ \ 333 | ts[r + (R)+2] = ts[r+(R)-1]; \ 334 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 335 | 336 | for (r=1;r < 2*RCNT;r+=2*SKEIN_UNROLL_512) /* loop thru it */ 337 | #endif /* end of looped code definitions */ 338 | { 339 | #define R512_8_rounds(R) /* do 8 full rounds */ \ 340 | R512(0,1,2,3,4,5,6,7,R_512_0,8*(R)+ 1); \ 341 | R512(2,1,4,7,6,5,0,3,R_512_1,8*(R)+ 2); \ 342 | R512(4,1,6,3,0,5,2,7,R_512_2,8*(R)+ 3); \ 343 | R512(6,1,0,7,2,5,4,3,R_512_3,8*(R)+ 4); \ 344 | I512(2*(R)); \ 345 | R512(0,1,2,3,4,5,6,7,R_512_4,8*(R)+ 5); \ 346 | R512(2,1,4,7,6,5,0,3,R_512_5,8*(R)+ 6); \ 347 | R512(4,1,6,3,0,5,2,7,R_512_6,8*(R)+ 7); \ 348 | R512(6,1,0,7,2,5,4,3,R_512_7,8*(R)+ 8); \ 349 | I512(2*(R)+1); /* and key injection */ 350 | 351 | R512_8_rounds( 0); 352 | 353 | #define R512_Unroll_R(NN) ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_512 > (NN))) 354 | 355 | #if R512_Unroll_R( 1) 356 | R512_8_rounds( 1); 357 | #endif 358 | #if R512_Unroll_R( 2) 359 | R512_8_rounds( 2); 360 | #endif 361 | #if R512_Unroll_R( 3) 362 | R512_8_rounds( 3); 363 | #endif 364 | #if R512_Unroll_R( 4) 365 | R512_8_rounds( 4); 366 | #endif 367 | #if R512_Unroll_R( 5) 368 | R512_8_rounds( 5); 369 | #endif 370 | #if R512_Unroll_R( 6) 371 | R512_8_rounds( 6); 372 | #endif 373 | #if R512_Unroll_R( 7) 374 | R512_8_rounds( 7); 375 | #endif 376 | #if R512_Unroll_R( 8) 377 | R512_8_rounds( 8); 378 | #endif 379 | #if R512_Unroll_R( 9) 380 | R512_8_rounds( 9); 381 | #endif 382 | #if R512_Unroll_R(10) 383 | R512_8_rounds(10); 384 | #endif 385 | #if R512_Unroll_R(11) 386 | R512_8_rounds(11); 387 | #endif 388 | #if R512_Unroll_R(12) 389 | R512_8_rounds(12); 390 | #endif 391 | #if R512_Unroll_R(13) 392 | R512_8_rounds(13); 393 | #endif 394 | #if R512_Unroll_R(14) 395 | R512_8_rounds(14); 396 | #endif 397 | #if (SKEIN_UNROLL_512 > 14) 398 | #error "need more unrolling in Skein_512_Process_Block" 399 | #endif 400 | } 401 | 402 | /* do the final "feedforward" xor, update context chaining vars */ 403 | ctx->X[0] = X0 ^ w[0]; 404 | ctx->X[1] = X1 ^ w[1]; 405 | ctx->X[2] = X2 ^ w[2]; 406 | ctx->X[3] = X3 ^ w[3]; 407 | ctx->X[4] = X4 ^ w[4]; 408 | ctx->X[5] = X5 ^ w[5]; 409 | ctx->X[6] = X6 ^ w[6]; 410 | ctx->X[7] = X7 ^ w[7]; 411 | Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); 412 | 413 | ts[1] &= ~SKEIN_T1_FLAG_FIRST; 414 | } 415 | while (--blkCnt); 416 | ctx->h.T[0] = ts[0]; 417 | ctx->h.T[1] = ts[1]; 418 | } 419 | 420 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 421 | size_t Skein_512_Process_Block_CodeSize(void) 422 | { 423 | return ((u08b_t *) Skein_512_Process_Block_CodeSize) - 424 | ((u08b_t *) Skein_512_Process_Block); 425 | } 426 | uint_t Skein_512_Unroll_Cnt(void) 427 | { 428 | return SKEIN_UNROLL_512; 429 | } 430 | #endif 431 | #endif 432 | 433 | /***************************** Skein1024 ******************************/ 434 | #if !(SKEIN_USE_ASM & 1024) 435 | void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx,const u08b_t *blkPtr,size_t blkCnt,size_t byteCntAdd) 436 | { /* do it in C, always looping (unrolled is bigger AND slower!) */ 437 | enum 438 | { 439 | WCNT = SKEIN1024_STATE_WORDS 440 | }; 441 | #undef RCNT 442 | #define RCNT (SKEIN1024_ROUNDS_TOTAL/8) 443 | 444 | #ifdef SKEIN_LOOP /* configure how much to unroll the loop */ 445 | #define SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10) 446 | #else 447 | #define SKEIN_UNROLL_1024 (0) 448 | #endif 449 | 450 | #if (SKEIN_UNROLL_1024 != 0) 451 | #if (RCNT % SKEIN_UNROLL_1024) 452 | #error "Invalid SKEIN_UNROLL_1024" /* sanity check on unroll count */ 453 | #endif 454 | size_t r; 455 | u64b_t kw[WCNT+4+RCNT*2]; /* key schedule words : chaining vars + tweak + "rotation"*/ 456 | #else 457 | u64b_t kw[WCNT+4]; /* key schedule words : chaining vars + tweak */ 458 | #endif 459 | 460 | u64b_t X00,X01,X02,X03,X04,X05,X06,X07, /* local copy of vars, for speed */ 461 | X08,X09,X10,X11,X12,X13,X14,X15; 462 | u64b_t w [WCNT]; /* local copy of input block */ 463 | #ifdef SKEIN_DEBUG 464 | const u64b_t *Xptr[16]; /* use for debugging (help compiler put Xn in registers) */ 465 | Xptr[ 0] = &X00; Xptr[ 1] = &X01; Xptr[ 2] = &X02; Xptr[ 3] = &X03; 466 | Xptr[ 4] = &X04; Xptr[ 5] = &X05; Xptr[ 6] = &X06; Xptr[ 7] = &X07; 467 | Xptr[ 8] = &X08; Xptr[ 9] = &X09; Xptr[10] = &X10; Xptr[11] = &X11; 468 | Xptr[12] = &X12; Xptr[13] = &X13; Xptr[14] = &X14; Xptr[15] = &X15; 469 | #endif 470 | 471 | Skein_assert(blkCnt != 0); /* never call with blkCnt == 0! */ 472 | ts[0] = ctx->h.T[0]; 473 | ts[1] = ctx->h.T[1]; 474 | do { 475 | /* this implementation only supports 2**64 input bytes (no carry out here) */ 476 | ts[0] += byteCntAdd; /* update processed length */ 477 | 478 | /* precompute the key schedule for this block */ 479 | ks[ 0] = ctx->X[ 0]; 480 | ks[ 1] = ctx->X[ 1]; 481 | ks[ 2] = ctx->X[ 2]; 482 | ks[ 3] = ctx->X[ 3]; 483 | ks[ 4] = ctx->X[ 4]; 484 | ks[ 5] = ctx->X[ 5]; 485 | ks[ 6] = ctx->X[ 6]; 486 | ks[ 7] = ctx->X[ 7]; 487 | ks[ 8] = ctx->X[ 8]; 488 | ks[ 9] = ctx->X[ 9]; 489 | ks[10] = ctx->X[10]; 490 | ks[11] = ctx->X[11]; 491 | ks[12] = ctx->X[12]; 492 | ks[13] = ctx->X[13]; 493 | ks[14] = ctx->X[14]; 494 | ks[15] = ctx->X[15]; 495 | ks[16] = ks[ 0] ^ ks[ 1] ^ ks[ 2] ^ ks[ 3] ^ 496 | ks[ 4] ^ ks[ 5] ^ ks[ 6] ^ ks[ 7] ^ 497 | ks[ 8] ^ ks[ 9] ^ ks[10] ^ ks[11] ^ 498 | ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY; 499 | 500 | ts[2] = ts[0] ^ ts[1]; 501 | 502 | Skein_Get64_LSB_First(w,blkPtr,WCNT); /* get input block in little-endian format */ 503 | DebugSaveTweak(ctx); 504 | Skein_Show_Block(BLK_BITS,&ctx->h,ctx->X,blkPtr,w,ks,ts); 505 | 506 | X00 = w[ 0] + ks[ 0]; /* do the first full key injection */ 507 | X01 = w[ 1] + ks[ 1]; 508 | X02 = w[ 2] + ks[ 2]; 509 | X03 = w[ 3] + ks[ 3]; 510 | X04 = w[ 4] + ks[ 4]; 511 | X05 = w[ 5] + ks[ 5]; 512 | X06 = w[ 6] + ks[ 6]; 513 | X07 = w[ 7] + ks[ 7]; 514 | X08 = w[ 8] + ks[ 8]; 515 | X09 = w[ 9] + ks[ 9]; 516 | X10 = w[10] + ks[10]; 517 | X11 = w[11] + ks[11]; 518 | X12 = w[12] + ks[12]; 519 | X13 = w[13] + ks[13] + ts[0]; 520 | X14 = w[14] + ks[14] + ts[1]; 521 | X15 = w[15] + ks[15]; 522 | 523 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INITIAL,Xptr); 524 | 525 | #define Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rNum) \ 526 | X##p0 += X##p1; X##p1 = RotL_64(X##p1,ROT##_0); X##p1 ^= X##p0; \ 527 | X##p2 += X##p3; X##p3 = RotL_64(X##p3,ROT##_1); X##p3 ^= X##p2; \ 528 | X##p4 += X##p5; X##p5 = RotL_64(X##p5,ROT##_2); X##p5 ^= X##p4; \ 529 | X##p6 += X##p7; X##p7 = RotL_64(X##p7,ROT##_3); X##p7 ^= X##p6; \ 530 | X##p8 += X##p9; X##p9 = RotL_64(X##p9,ROT##_4); X##p9 ^= X##p8; \ 531 | X##pA += X##pB; X##pB = RotL_64(X##pB,ROT##_5); X##pB ^= X##pA; \ 532 | X##pC += X##pD; X##pD = RotL_64(X##pD,ROT##_6); X##pD ^= X##pC; \ 533 | X##pE += X##pF; X##pF = RotL_64(X##pF,ROT##_7); X##pF ^= X##pE; \ 534 | 535 | #if SKEIN_UNROLL_1024 == 0 536 | #define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ 537 | Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ 538 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,rn,Xptr); 539 | 540 | #define I1024(R) \ 541 | X00 += ks[((R)+ 1) % 17]; /* inject the key schedule value */ \ 542 | X01 += ks[((R)+ 2) % 17]; \ 543 | X02 += ks[((R)+ 3) % 17]; \ 544 | X03 += ks[((R)+ 4) % 17]; \ 545 | X04 += ks[((R)+ 5) % 17]; \ 546 | X05 += ks[((R)+ 6) % 17]; \ 547 | X06 += ks[((R)+ 7) % 17]; \ 548 | X07 += ks[((R)+ 8) % 17]; \ 549 | X08 += ks[((R)+ 9) % 17]; \ 550 | X09 += ks[((R)+10) % 17]; \ 551 | X10 += ks[((R)+11) % 17]; \ 552 | X11 += ks[((R)+12) % 17]; \ 553 | X12 += ks[((R)+13) % 17]; \ 554 | X13 += ks[((R)+14) % 17] + ts[((R)+1) % 3]; \ 555 | X14 += ks[((R)+15) % 17] + ts[((R)+2) % 3]; \ 556 | X15 += ks[((R)+16) % 17] + (R)+1; \ 557 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 558 | #else /* looping version */ 559 | #define R1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ 560 | Round1024(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pA,pB,pC,pD,pE,pF,ROT,rn) \ 561 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,4*(r-1)+rn,Xptr); 562 | 563 | #define I1024(R) \ 564 | X00 += ks[r+(R)+ 0]; /* inject the key schedule value */ \ 565 | X01 += ks[r+(R)+ 1]; \ 566 | X02 += ks[r+(R)+ 2]; \ 567 | X03 += ks[r+(R)+ 3]; \ 568 | X04 += ks[r+(R)+ 4]; \ 569 | X05 += ks[r+(R)+ 5]; \ 570 | X06 += ks[r+(R)+ 6]; \ 571 | X07 += ks[r+(R)+ 7]; \ 572 | X08 += ks[r+(R)+ 8]; \ 573 | X09 += ks[r+(R)+ 9]; \ 574 | X10 += ks[r+(R)+10]; \ 575 | X11 += ks[r+(R)+11]; \ 576 | X12 += ks[r+(R)+12]; \ 577 | X13 += ks[r+(R)+13] + ts[r+(R)+0]; \ 578 | X14 += ks[r+(R)+14] + ts[r+(R)+1]; \ 579 | X15 += ks[r+(R)+15] + r+(R) ; \ 580 | ks[r + (R)+16] = ks[r+(R)-1]; /* rotate key schedule */ \ 581 | ts[r + (R)+ 2] = ts[r+(R)-1]; \ 582 | Skein_Show_R_Ptr(BLK_BITS,&ctx->h,SKEIN_RND_KEY_INJECT,Xptr); 583 | 584 | for (r=1;r <= 2*RCNT;r+=2*SKEIN_UNROLL_1024) /* loop thru it */ 585 | #endif 586 | { 587 | #define R1024_8_rounds(R) /* do 8 full rounds */ \ 588 | R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_0,8*(R) + 1); \ 589 | R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_1,8*(R) + 2); \ 590 | R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_2,8*(R) + 3); \ 591 | R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_3,8*(R) + 4); \ 592 | I1024(2*(R)); \ 593 | R1024(00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,R1024_4,8*(R) + 5); \ 594 | R1024(00,09,02,13,06,11,04,15,10,07,12,03,14,05,08,01,R1024_5,8*(R) + 6); \ 595 | R1024(00,07,02,05,04,03,06,01,12,15,14,13,08,11,10,09,R1024_6,8*(R) + 7); \ 596 | R1024(00,15,02,11,06,13,04,09,14,01,08,05,10,03,12,07,R1024_7,8*(R) + 8); \ 597 | I1024(2*(R)+1); 598 | 599 | R1024_8_rounds( 0); 600 | 601 | #define R1024_Unroll_R(NN) ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || (SKEIN_UNROLL_1024 > (NN))) 602 | 603 | #if R1024_Unroll_R( 1) 604 | R1024_8_rounds( 1); 605 | #endif 606 | #if R1024_Unroll_R( 2) 607 | R1024_8_rounds( 2); 608 | #endif 609 | #if R1024_Unroll_R( 3) 610 | R1024_8_rounds( 3); 611 | #endif 612 | #if R1024_Unroll_R( 4) 613 | R1024_8_rounds( 4); 614 | #endif 615 | #if R1024_Unroll_R( 5) 616 | R1024_8_rounds( 5); 617 | #endif 618 | #if R1024_Unroll_R( 6) 619 | R1024_8_rounds( 6); 620 | #endif 621 | #if R1024_Unroll_R( 7) 622 | R1024_8_rounds( 7); 623 | #endif 624 | #if R1024_Unroll_R( 8) 625 | R1024_8_rounds( 8); 626 | #endif 627 | #if R1024_Unroll_R( 9) 628 | R1024_8_rounds( 9); 629 | #endif 630 | #if R1024_Unroll_R(10) 631 | R1024_8_rounds(10); 632 | #endif 633 | #if R1024_Unroll_R(11) 634 | R1024_8_rounds(11); 635 | #endif 636 | #if R1024_Unroll_R(12) 637 | R1024_8_rounds(12); 638 | #endif 639 | #if R1024_Unroll_R(13) 640 | R1024_8_rounds(13); 641 | #endif 642 | #if R1024_Unroll_R(14) 643 | R1024_8_rounds(14); 644 | #endif 645 | #if (SKEIN_UNROLL_1024 > 14) 646 | #error "need more unrolling in Skein_1024_Process_Block" 647 | #endif 648 | } 649 | /* do the final "feedforward" xor, update context chaining vars */ 650 | 651 | ctx->X[ 0] = X00 ^ w[ 0]; 652 | ctx->X[ 1] = X01 ^ w[ 1]; 653 | ctx->X[ 2] = X02 ^ w[ 2]; 654 | ctx->X[ 3] = X03 ^ w[ 3]; 655 | ctx->X[ 4] = X04 ^ w[ 4]; 656 | ctx->X[ 5] = X05 ^ w[ 5]; 657 | ctx->X[ 6] = X06 ^ w[ 6]; 658 | ctx->X[ 7] = X07 ^ w[ 7]; 659 | ctx->X[ 8] = X08 ^ w[ 8]; 660 | ctx->X[ 9] = X09 ^ w[ 9]; 661 | ctx->X[10] = X10 ^ w[10]; 662 | ctx->X[11] = X11 ^ w[11]; 663 | ctx->X[12] = X12 ^ w[12]; 664 | ctx->X[13] = X13 ^ w[13]; 665 | ctx->X[14] = X14 ^ w[14]; 666 | ctx->X[15] = X15 ^ w[15]; 667 | 668 | Skein_Show_Round(BLK_BITS,&ctx->h,SKEIN_RND_FEED_FWD,ctx->X); 669 | 670 | ts[1] &= ~SKEIN_T1_FLAG_FIRST; 671 | blkPtr += SKEIN1024_BLOCK_BYTES; 672 | } 673 | while (--blkCnt); 674 | ctx->h.T[0] = ts[0]; 675 | ctx->h.T[1] = ts[1]; 676 | } 677 | 678 | #if defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF) 679 | size_t Skein1024_Process_Block_CodeSize(void) 680 | { 681 | return ((u08b_t *) Skein1024_Process_Block_CodeSize) - 682 | ((u08b_t *) Skein1024_Process_Block); 683 | } 684 | uint_t Skein1024_Unroll_Cnt(void) 685 | { 686 | return SKEIN_UNROLL_1024; 687 | } 688 | #endif 689 | #endif 690 | -------------------------------------------------------------------------------- /c_src/skein_debug.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | ** 3 | ** Debug output functions for Skein hashing. 4 | ** 5 | ** Source code author: Doug Whiting, 2008. 6 | ** 7 | ** This algorithm and source code is released to the public domain. 8 | ** 9 | ************************************************************************/ 10 | #include 11 | 12 | #ifdef SKEIN_DEBUG /* only instantiate this code if SKEIN_DEBUG is on */ 13 | #include "skein.h" 14 | 15 | static const char *INDENT = " "; /* how much to indent on new line */ 16 | 17 | uint_t skein_DebugFlag = 0; /* off by default. Must be set externally */ 18 | 19 | static void Show64(size_t cnt,const u64b_t *X) 20 | { 21 | size_t i; 22 | for (i=0;i < cnt;i++) 23 | { 24 | if (i % 4 == 0) printf(INDENT); 25 | printf(" %08X.%08X ",(uint_32t)(X[i] >> 32),(uint_32t)X[i]); 26 | if (i % 4 == 3 || i==cnt-1) printf("\n"); 27 | } 28 | } 29 | 30 | static void Show08(size_t cnt,const u08b_t *b) 31 | { 32 | size_t i; 33 | for (i=0;i < cnt;i++) 34 | { 35 | if (i %16 == 0) printf(INDENT); 36 | else if (i % 4 == 0) printf(" "); 37 | printf(" %02X",b[i]); 38 | if (i %16 == 15 || i==cnt-1) printf("\n"); 39 | } 40 | } 41 | 42 | static const char *AlgoHeader(uint_t bits) 43 | { 44 | if (skein_DebugFlag & SKEIN_DEBUG_THREEFISH) 45 | switch (bits) 46 | { 47 | case 256: return ":Threefish-256: "; 48 | case 512: return ":Threefish-512: "; 49 | case 1024: return ":Threefish-1024:"; 50 | } 51 | else 52 | switch (bits) 53 | { 54 | case 256: return ":Skein-256: "; 55 | case 512: return ":Skein-512: "; 56 | case 1024: return ":Skein-1024:"; 57 | } 58 | return NULL; 59 | } 60 | 61 | void Skein_Show_Final(uint_t bits,const Skein_Ctxt_Hdr_t *h,size_t cnt,const u08b_t *outPtr) 62 | { 63 | if (skein_DebugFlag & SKEIN_DEBUG_CONFIG || ((h->T[1] & SKEIN_T1_BLK_TYPE_MASK) != SKEIN_T1_BLK_TYPE_CFG)) 64 | if (skein_DebugFlag & SKEIN_DEBUG_FINAL) 65 | { 66 | printf("\n%s Final output=\n",AlgoHeader(bits)); 67 | Show08(cnt,outPtr); 68 | printf(" ++++++++++\n"); 69 | } 70 | } 71 | 72 | /* show state after a round (or "pseudo-round") */ 73 | void Skein_Show_Round(uint_t bits,const Skein_Ctxt_Hdr_t *h,size_t r,const u64b_t *X) 74 | { 75 | static uint_t injectNum=0; /* not multi-thread safe! */ 76 | 77 | if (skein_DebugFlag & SKEIN_DEBUG_CONFIG || ((h->T[1] & SKEIN_T1_BLK_TYPE_MASK) != SKEIN_T1_BLK_TYPE_CFG)) 78 | if (skein_DebugFlag) 79 | { 80 | if (r >= SKEIN_RND_SPECIAL) 81 | { /* a key injection (or feedforward) point */ 82 | injectNum = (r == SKEIN_RND_KEY_INITIAL) ? 0 : injectNum+1; 83 | if ( skein_DebugFlag & SKEIN_DEBUG_INJECT || 84 | ((skein_DebugFlag & SKEIN_DEBUG_FINAL) && r == SKEIN_RND_FEED_FWD)) 85 | { 86 | printf("\n%s",AlgoHeader(bits)); 87 | switch (r) 88 | { 89 | case SKEIN_RND_KEY_INITIAL: 90 | printf(" [state after initial key injection]"); 91 | break; 92 | case SKEIN_RND_KEY_INJECT: 93 | printf(" [state after key injection #%02d]",injectNum); 94 | break; 95 | case SKEIN_RND_FEED_FWD: 96 | printf(" [state after plaintext feedforward]"); 97 | injectNum = 0; 98 | break; 99 | } 100 | printf("=\n"); 101 | Show64(bits/64,X); 102 | if (r== SKEIN_RND_FEED_FWD) 103 | printf(" ----------\n"); 104 | } 105 | } 106 | else if (skein_DebugFlag & SKEIN_DEBUG_ROUNDS) 107 | { 108 | uint_t j; 109 | u64b_t p[SKEIN_MAX_STATE_WORDS]; 110 | const u08b_t *perm; 111 | const static u08b_t PERM_256 [4][ 4] = { { 0,1,2,3 }, { 0,3,2,1 }, { 0,1,2,3 }, { 0,3,2,1 } }; 112 | const static u08b_t PERM_512 [4][ 8] = { { 0,1,2,3,4,5,6,7 }, 113 | { 2,1,4,7,6,5,0,3 }, 114 | { 4,1,6,3,0,5,2,7 }, 115 | { 6,1,0,7,2,5,4,3 } 116 | }; 117 | const static u08b_t PERM_1024[4][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }, 118 | { 0, 9, 2,13, 6,11, 4,15,10, 7,12, 3,14, 5, 8, 1 }, 119 | { 0, 7, 2, 5, 4, 3, 6, 1,12,15,14,13, 8,11,10, 9 }, 120 | { 0,15, 2,11, 6,13, 4, 9,14, 1, 8, 5,10, 3,12, 7 } 121 | }; 122 | 123 | if ((skein_DebugFlag & SKEIN_DEBUG_PERMUTE) && (r & 3)) 124 | { 125 | printf("\n%s [state after round %2d (permuted)]=\n",AlgoHeader(bits),r); 126 | switch (bits) 127 | { 128 | case 256: perm = PERM_256 [r&3]; break; 129 | case 512: perm = PERM_512 [r&3]; break; 130 | default: perm = PERM_1024[r&3]; break; 131 | } 132 | for (j=0;jT[1] & SKEIN_T1_BLK_TYPE_MASK) != SKEIN_T1_BLK_TYPE_CFG)) 163 | if (skein_DebugFlag) 164 | { 165 | if (skein_DebugFlag & SKEIN_DEBUG_HDR) 166 | { 167 | printf("\n%s Block: outBits=%4d. T0=%06X.",AlgoHeader(bits),(uint_t) h->hashBitLen,(uint_t)h->T[0]); 168 | printf(" Type="); 169 | n = (uint_t) ((h->T[1] & SKEIN_T1_BLK_TYPE_MASK) >> SKEIN_T1_POS_BLK_TYPE); 170 | switch (n) 171 | { 172 | case SKEIN_BLK_TYPE_KEY: printf("KEY. "); break; 173 | case SKEIN_BLK_TYPE_CFG: printf("CFG. "); break; 174 | case SKEIN_BLK_TYPE_PERS: printf("PERS."); break; 175 | case SKEIN_BLK_TYPE_PK : printf("PK. "); break; 176 | case SKEIN_BLK_TYPE_KDF: printf("KDF. "); break; 177 | case SKEIN_BLK_TYPE_MSG: printf("MSG. "); break; 178 | case SKEIN_BLK_TYPE_OUT: printf("OUT. "); break; 179 | default: printf("0x%02X.",n); break; 180 | } 181 | printf(" Flags="); 182 | printf((h->T[1] & SKEIN_T1_FLAG_FIRST) ? " First":" "); 183 | printf((h->T[1] & SKEIN_T1_FLAG_FINAL) ? " Final":" "); 184 | printf((h->T[1] & SKEIN_T1_FLAG_BIT_PAD) ? " Pad" :" "); 185 | n = (uint_t) ((h->T[1] & SKEIN_T1_TREE_LVL_MASK) >> SKEIN_T1_POS_TREE_LVL); 186 | if (n) 187 | printf(" TreeLevel = %02X",n); 188 | printf("\n"); 189 | } 190 | if (skein_DebugFlag & SKEIN_DEBUG_TWEAK) 191 | { 192 | printf(" Tweak:\n"); 193 | Show64(2,h->T); 194 | } 195 | if (skein_DebugFlag & SKEIN_DEBUG_STATE) 196 | { 197 | printf(" %s words:\n",(skein_DebugFlag & SKEIN_DEBUG_THREEFISH)?"Key":"State"); 198 | Show64(bits/64,X); 199 | } 200 | if (skein_DebugFlag & SKEIN_DEBUG_KEYSCHED) 201 | { 202 | printf(" Tweak schedule:\n"); 203 | Show64(3,tsPtr); 204 | printf(" Key schedule:\n"); 205 | Show64((bits/64)+1,ksPtr); 206 | } 207 | if (skein_DebugFlag & SKEIN_DEBUG_INPUT_64) 208 | { 209 | printf(" Input block (words):\n"); 210 | Show64(bits/64,wPtr); 211 | } 212 | if (skein_DebugFlag & SKEIN_DEBUG_INPUT_08) 213 | { 214 | printf(" Input block (bytes):\n"); 215 | Show08(bits/8,blkPtr); 216 | } 217 | } 218 | } 219 | 220 | void Skein_Show_Key(uint_t bits,const Skein_Ctxt_Hdr_t *h,const u08b_t *key,size_t keyBytes) 221 | { 222 | if (keyBytes) 223 | if (skein_DebugFlag & SKEIN_DEBUG_CONFIG || ((h->T[1] & SKEIN_T1_BLK_TYPE_MASK) != SKEIN_T1_BLK_TYPE_CFG)) 224 | if (skein_DebugFlag & SKEIN_DEBUG_KEY) 225 | { 226 | printf("\n%s MAC key = %4u bytes\n",AlgoHeader(bits),keyBytes); 227 | Show08(keyBytes,key); 228 | } 229 | } 230 | #endif 231 | -------------------------------------------------------------------------------- /c_src/skein_debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKEIN_DEBUG_H_ 2 | #define _SKEIN_DEBUG_H_ 3 | /*********************************************************************** 4 | ** 5 | ** Interface definitions for Skein hashing debug output. 6 | ** 7 | ** Source code author: Doug Whiting, 2008. 8 | ** 9 | ** This algorithm and source code is released to the public domain. 10 | ** 11 | ************************************************************************/ 12 | 13 | #ifdef SKEIN_DEBUG 14 | /* callout functions used inside Skein code */ 15 | void Skein_Show_Block(uint_t bits,const Skein_Ctxt_Hdr_t *h,const u64b_t *X,const u08b_t *blkPtr, 16 | const u64b_t *wPtr,const u64b_t *ksPtr,const u64b_t *tsPtr); 17 | void Skein_Show_Round(uint_t bits,const Skein_Ctxt_Hdr_t *h,size_t r,const u64b_t *X); 18 | void Skein_Show_R_Ptr(uint_t bits,const Skein_Ctxt_Hdr_t *h,size_t r,const u64b_t *X_ptr[]); 19 | void Skein_Show_Final(uint_t bits,const Skein_Ctxt_Hdr_t *h,size_t cnt,const u08b_t *outPtr); 20 | void Skein_Show_Key (uint_t bits,const Skein_Ctxt_Hdr_t *h,const u08b_t *key,size_t keyBytes); 21 | 22 | extern uint_t skein_DebugFlag; /* flags to control debug output (0 --> none) */ 23 | 24 | #define SKEIN_RND_SPECIAL (1000u) 25 | #define SKEIN_RND_KEY_INITIAL (SKEIN_RND_SPECIAL+0u) 26 | #define SKEIN_RND_KEY_INJECT (SKEIN_RND_SPECIAL+1u) 27 | #define SKEIN_RND_FEED_FWD (SKEIN_RND_SPECIAL+2u) 28 | 29 | /* flag bits: skein_DebugFlag */ 30 | #define SKEIN_DEBUG_KEY (1u << 1) /* show MAC key */ 31 | #define SKEIN_DEBUG_CONFIG (1u << 2) /* show config block processing */ 32 | #define SKEIN_DEBUG_STATE (1u << 3) /* show input state during Show_Block() */ 33 | #define SKEIN_DEBUG_TWEAK (1u << 4) /* show input state during Show_Block() */ 34 | #define SKEIN_DEBUG_KEYSCHED (1u << 5) /* show expanded key schedule */ 35 | #define SKEIN_DEBUG_INPUT_64 (1u << 6) /* show input block as 64-bit words */ 36 | #define SKEIN_DEBUG_INPUT_08 (1u << 7) /* show input block as 8-bit bytes */ 37 | #define SKEIN_DEBUG_INJECT (1u << 8) /* show state after key injection & feedforward points */ 38 | #define SKEIN_DEBUG_ROUNDS (1u << 9) /* show state after all rounds */ 39 | #define SKEIN_DEBUG_FINAL (1u <<10) /* show final output of Skein */ 40 | #define SKEIN_DEBUG_HDR (1u <<11) /* show block header */ 41 | #define SKEIN_DEBUG_THREEFISH (1u <<12) /* use Threefish name instead of Skein */ 42 | #define SKEIN_DEBUG_PERMUTE (1u <<13) /* use word permutations */ 43 | #define SKEIN_DEBUG_ALL ((~0u) & ~(SKEIN_DEBUG_THREEFISH | SKEIN_DEBUG_PERMUTE)) 44 | #define THREEFISH_DEBUG_ALL (SKEIN_DEBUG_ALL | SKEIN_DEBUG_THREEFISH) 45 | 46 | #endif /* SKEIN_DEBUG */ 47 | 48 | #endif /* _SKEIN_DEBUG_H_ */ 49 | -------------------------------------------------------------------------------- /c_src/skein_iv.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKEIN_IV_H_ 2 | #define _SKEIN_IV_H_ 3 | 4 | #include "skein.h" /* get Skein macros and types */ 5 | 6 | /* 7 | ***************** Pre-computed Skein IVs ******************* 8 | ** 9 | ** NOTE: these values are not "magic" constants, but 10 | ** are generated using the Threefish block function. 11 | ** They are pre-computed here only for speed; i.e., to 12 | ** avoid the need for a Threefish call during Init(). 13 | ** 14 | ** The IV for any fixed hash length may be pre-computed. 15 | ** Only the most common values are included here. 16 | ** 17 | ************************************************************ 18 | **/ 19 | 20 | #define MK_64 SKEIN_MK_64 21 | 22 | /* blkSize = 256 bits. hashSize = 128 bits */ 23 | const u64b_t SKEIN_256_IV_128[] = 24 | { 25 | MK_64(0x46B39C3A,0xAA418D4F), 26 | MK_64(0x681229DD,0x06920827), 27 | MK_64(0xCBE067C9,0x78460238), 28 | MK_64(0xC388A1B7,0x4EC45EF3) 29 | }; 30 | 31 | /* blkSize = 256 bits. hashSize = 160 bits */ 32 | const u64b_t SKEIN_256_IV_160[] = 33 | { 34 | MK_64(0xD51846B9,0xDAE51FBB), 35 | MK_64(0x7D47BABD,0x6205526D), 36 | MK_64(0xA1A8703E,0x47B89F20), 37 | MK_64(0xB97D7234,0xC5927589) 38 | }; 39 | 40 | /* blkSize = 256 bits. hashSize = 224 bits */ 41 | const u64b_t SKEIN_256_IV_224[] = 42 | { 43 | MK_64(0xFE6720F4,0x5ED90A57), 44 | MK_64(0x352D51F3,0xB01B6FBC), 45 | MK_64(0xD764B04F,0x1785F14E), 46 | MK_64(0xE7F24611,0xDDD59B27) 47 | }; 48 | 49 | /* blkSize = 256 bits. hashSize = 256 bits */ 50 | const u64b_t SKEIN_256_IV_256[] = 51 | { 52 | MK_64(0x164290A9,0xD4EEEF1D), 53 | MK_64(0x8E7EAF44,0xB1B0CD15), 54 | MK_64(0xA8BA0822,0xF69D09AE), 55 | MK_64(0x0AF25C5E,0x364A6468) 56 | }; 57 | 58 | /* blkSize = 512 bits. hashSize = 128 bits */ 59 | const u64b_t SKEIN_512_IV_128[] = 60 | { 61 | MK_64(0x51AF0A1B,0x97A7DA9C), 62 | MK_64(0xEC77F8A5,0xF4C6004C), 63 | MK_64(0x0BB7182C,0x25CA1F6E), 64 | MK_64(0x1B22A2CB,0x9F9339C5), 65 | MK_64(0xC905E0A4,0x31216AA4), 66 | MK_64(0xAEE4D5D0,0xBD378696), 67 | MK_64(0x92744A50,0x1953D08A), 68 | MK_64(0x2DCAD6F9,0x85777E17) 69 | }; 70 | 71 | /* blkSize = 512 bits. hashSize = 160 bits */ 72 | const u64b_t SKEIN_512_IV_160[] = 73 | { 74 | MK_64(0x9A73479A,0xC7701247), 75 | MK_64(0xD657FBF8,0xFDE0DA1A), 76 | MK_64(0xB1EE72A6,0xB04DA375), 77 | MK_64(0xE87ED2A1,0xC20605B8), 78 | MK_64(0x220A0EFA,0x9B925E17), 79 | MK_64(0x6D72A217,0xEAF0B419), 80 | MK_64(0x6CD72290,0xAA33FA72), 81 | MK_64(0x5829089E,0x759C4256) 82 | }; 83 | 84 | /* blkSize = 512 bits. hashSize = 224 bits */ 85 | const u64b_t SKEIN_512_IV_224[] = 86 | { 87 | MK_64(0x10C55045,0x6BF94560), 88 | MK_64(0x59004AF1,0xF558ACCC), 89 | MK_64(0x82BD1BF9,0xB7461DFD), 90 | MK_64(0x46B0F3A4,0x7C2AF60E), 91 | MK_64(0xECC8498C,0xE80A8DCA), 92 | MK_64(0x50A1DA33,0x10C836EF), 93 | MK_64(0x3538F92A,0x39165A80), 94 | MK_64(0x896A4329,0xCD5DCF2A) 95 | }; 96 | 97 | /* blkSize = 512 bits. hashSize = 256 bits */ 98 | const u64b_t SKEIN_512_IV_256[] = 99 | { 100 | MK_64(0x85A195B1,0x8B2264EC), 101 | MK_64(0x7A6DAC64,0xC047C2B0), 102 | MK_64(0xE1A21465,0xEE3FE124), 103 | MK_64(0x1D211735,0x6504425A), 104 | MK_64(0xC962DC0F,0xC0046F2C), 105 | MK_64(0x8D5A3E90,0x4B1BE9C8), 106 | MK_64(0xAFB7174B,0xBD8FEEE9), 107 | MK_64(0x7FE63D9B,0xF94EDEB8) 108 | }; 109 | 110 | /* blkSize = 512 bits. hashSize = 384 bits */ 111 | const u64b_t SKEIN_512_IV_384[] = 112 | { 113 | MK_64(0x755C4957,0x16D7512B), 114 | MK_64(0xB4587127,0x14DF4CEF), 115 | MK_64(0x677D2E8C,0x027C060A), 116 | MK_64(0x8DA4F592,0x05232716), 117 | MK_64(0xCE454B58,0xC445AD7F), 118 | MK_64(0x23048344,0xACA8BC96), 119 | MK_64(0xF719BCC3,0x38768323), 120 | MK_64(0xD77E3686,0x50579DEC) 121 | }; 122 | 123 | /* blkSize = 512 bits. hashSize = 512 bits */ 124 | const u64b_t SKEIN_512_IV_512[] = 125 | { 126 | MK_64(0x1A9A721C,0x8A265CA5), 127 | MK_64(0xC9ABACF5,0xAA853978), 128 | MK_64(0x4AF6652A,0xB80A2883), 129 | MK_64(0x66F5E8A8,0x09A773C7), 130 | MK_64(0x7FA984B7,0x81BAAF5B), 131 | MK_64(0x0FE5D2D9,0x3233F397), 132 | MK_64(0x6E29F932,0xDCB412D7), 133 | MK_64(0xD40CD947,0x2F225C23) 134 | }; 135 | 136 | /* blkSize = 1024 bits. hashSize = 384 bits */ 137 | const u64b_t SKEIN1024_IV_384[] = 138 | { 139 | MK_64(0x9E887D47,0x2693F556), 140 | MK_64(0xF4553A5A,0xB3A902D8), 141 | MK_64(0x60A10790,0x28E4504E), 142 | MK_64(0x96FAA39D,0x943F8ABE), 143 | MK_64(0x2A769D27,0x828A22A7), 144 | MK_64(0xB2F274F5,0xB2C3A833), 145 | MK_64(0xC722C052,0x47F09222), 146 | MK_64(0x377C4A92,0xEE78B216), 147 | MK_64(0x97CFE7B2,0x039F4C9D), 148 | MK_64(0xC864ACFA,0xC83C8364), 149 | MK_64(0x73F26579,0x1D3CF723), 150 | MK_64(0x2464DC1E,0x5E327F97), 151 | MK_64(0x135D3954,0xF181CB1A), 152 | MK_64(0x244BBF13,0x24C5C669), 153 | MK_64(0xE1E258BC,0x446662E3), 154 | MK_64(0xCF1E0F47,0x934A469C) 155 | }; 156 | 157 | /* blkSize = 1024 bits. hashSize = 512 bits */ 158 | const u64b_t SKEIN1024_IV_512[] = 159 | { 160 | MK_64(0x76066F1F,0x612DD519), 161 | MK_64(0xD9B93D95,0x75D90191), 162 | MK_64(0x582D15EA,0x89696586), 163 | MK_64(0x4F1CA328,0xB5F10FB3), 164 | MK_64(0x686C454D,0xEC64B419), 165 | MK_64(0x2D7BD9B4,0x026EDABE), 166 | MK_64(0xEF346195,0x1ACD05C4), 167 | MK_64(0x1759E898,0x4446E275), 168 | MK_64(0xACFC075A,0xE724456D), 169 | MK_64(0x82F35D0A,0xE7704311), 170 | MK_64(0x99D0B103,0x9AD7E344), 171 | MK_64(0x85D6C81D,0x29F6204B), 172 | MK_64(0x0CA2A987,0x5D57632A), 173 | MK_64(0x069A8931,0x47A448FA), 174 | MK_64(0x3C42FB50,0x02815320), 175 | MK_64(0xF7E22C15,0x953E3125) 176 | }; 177 | 178 | /* blkSize = 1024 bits. hashSize = 1024 bits */ 179 | const u64b_t SKEIN1024_IV_1024[] = 180 | { 181 | MK_64(0x495E85B9,0x53876965), 182 | MK_64(0x1E3D5C1B,0x41E754EF), 183 | MK_64(0x23725455,0x2E9C10C7), 184 | MK_64(0x0B00AAB4,0xFA441407), 185 | MK_64(0x17DDA56A,0xA106337C), 186 | MK_64(0xF98200E9,0xCAE13F94), 187 | MK_64(0xF2DF7F00,0xADFF12BF), 188 | MK_64(0xA92673D0,0xD0CA7AD9), 189 | MK_64(0xC0DD64B0,0x4B27ED98), 190 | MK_64(0x87C36A6C,0xA0A26F90), 191 | MK_64(0x640C8526,0xD0850A10), 192 | MK_64(0x6EBFAD0C,0x93DA09AE), 193 | MK_64(0x617E3BCD,0xDEE4A85F), 194 | MK_64(0x05A4A1A7,0xD82737B7), 195 | MK_64(0x002BAF2C,0x3EB13D30), 196 | MK_64(0x28527A78,0xC83D554C) 197 | }; 198 | 199 | #endif /* _SKEIN_IV_H_ */ 200 | -------------------------------------------------------------------------------- /c_src/skein_port.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKEIN_PORT_H_ 2 | #define _SKEIN_PORT_H_ 3 | /******************************************************************* 4 | ** 5 | ** Platform-specific definitions for Skein hash function. 6 | ** 7 | ** Source code author: Doug Whiting, 2008. 8 | ** 9 | ** This algorithm and source code is released to the public domain. 10 | ** 11 | ** Many thanks to Brian Gladman for his portable header files. 12 | ** 13 | ** To port Skein to an "unsupported" platform, change the definitions 14 | ** in this file appropriately. 15 | ** 16 | ********************************************************************/ 17 | 18 | #include "brg_types.h" /* get integer type definitions */ 19 | 20 | typedef unsigned int uint_t; /* native unsigned integer */ 21 | typedef uint_8t u08b_t; /* 8-bit unsigned integer */ 22 | typedef uint_64t u64b_t; /* 64-bit unsigned integer */ 23 | 24 | #ifndef RotL_64 25 | #define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N)))) 26 | #endif 27 | 28 | /* 29 | * Skein is "natively" little-endian (unlike SHA-xxx), for optimal 30 | * performance on x86 CPUs. The Skein code requires the following 31 | * definitions for dealing with endianness: 32 | * 33 | * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian 34 | * Skein_Put64_LSB_First 35 | * Skein_Get64_LSB_First 36 | * Skein_Swap64 37 | * 38 | * If SKEIN_NEED_SWAP is defined at compile time, it is used here 39 | * along with the portable versions of Put64/Get64/Swap64, which 40 | * are slow in general. 41 | * 42 | * Otherwise, an "auto-detect" of endianness is attempted below. 43 | * If the default handling doesn't work well, the user may insert 44 | * platform-specific code instead (e.g., for big-endian CPUs). 45 | * 46 | */ 47 | #ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */ 48 | 49 | #include "brg_endian.h" /* get endianness selection */ 50 | #if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN 51 | /* here for big-endian CPUs */ 52 | #define SKEIN_NEED_SWAP (1) 53 | #elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN 54 | /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */ 55 | #define SKEIN_NEED_SWAP (0) 56 | #if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */ 57 | #define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt) 58 | #define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt)) 59 | #endif 60 | #else 61 | #error "Skein needs endianness setting!" 62 | #endif 63 | 64 | #endif /* ifndef SKEIN_NEED_SWAP */ 65 | 66 | /* 67 | ****************************************************************** 68 | * Provide any definitions still needed. 69 | ****************************************************************** 70 | */ 71 | #ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */ 72 | #if SKEIN_NEED_SWAP 73 | #define Skein_Swap64(w64) \ 74 | ( (( ((u64b_t)(w64)) & 0xFF) << 56) | \ 75 | (((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \ 76 | (((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \ 77 | (((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \ 78 | (((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \ 79 | (((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \ 80 | (((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \ 81 | (((((u64b_t)(w64)) >>56) & 0xFF) ) ) 82 | #else 83 | #define Skein_Swap64(w64) (w64) 84 | #endif 85 | #endif /* ifndef Skein_Swap64 */ 86 | 87 | 88 | #ifndef Skein_Put64_LSB_First 89 | void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt) 90 | #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ 91 | { /* this version is fully portable (big-endian or little-endian), but slow */ 92 | size_t n; 93 | 94 | for (n=0;n>3] >> (8*(n&7))); 96 | } 97 | #else 98 | ; /* output only the function prototype */ 99 | #endif 100 | #endif /* ifndef Skein_Put64_LSB_First */ 101 | 102 | 103 | #ifndef Skein_Get64_LSB_First 104 | void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) 105 | #ifdef SKEIN_PORT_CODE /* instantiate the function code here? */ 106 | { /* this version is fully portable (big-endian or little-endian), but slow */ 107 | size_t n; 108 | 109 | for (n=0;n<8*wCnt;n+=8) 110 | dst[n/8] = (((u64b_t) src[n ]) ) + 111 | (((u64b_t) src[n+1]) << 8) + 112 | (((u64b_t) src[n+2]) << 16) + 113 | (((u64b_t) src[n+3]) << 24) + 114 | (((u64b_t) src[n+4]) << 32) + 115 | (((u64b_t) src[n+5]) << 40) + 116 | (((u64b_t) src[n+6]) << 48) + 117 | (((u64b_t) src[n+7]) << 56) ; 118 | } 119 | #else 120 | ; /* output only the function prototype */ 121 | #endif 122 | #endif /* ifndef Skein_Get64_LSB_First */ 123 | 124 | #endif /* ifndef _SKEIN_PORT_H_ */ 125 | -------------------------------------------------------------------------------- /c_src/skerl_nifs.c: -------------------------------------------------------------------------------- 1 | 2 | #include "erl_nif.h" 3 | #include "erl_nif_compat.h" 4 | #include "skein_api.h" 5 | #include 6 | 7 | static ErlNifResourceType* skein_hashstate; 8 | 9 | typedef struct 10 | { 11 | } skein_handle; 12 | 13 | // Prototypes 14 | ERL_NIF_TERM skein_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 15 | ERL_NIF_TERM skein_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 16 | ERL_NIF_TERM skein_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 17 | ERL_NIF_TERM skein_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); 18 | // lifecycle 19 | int load(ErlNifEnv* env, void ** priv_data, ERL_NIF_TERM load_info); 20 | 21 | static ErlNifFunc nif_funcs[] = 22 | { 23 | {"init", 1, skein_init}, 24 | {"update", 2, skein_update}, 25 | {"final", 1, skein_final}, 26 | {"hash", 2, skein_hash} 27 | }; 28 | 29 | ERL_NIF_INIT(skerl, nif_funcs, load, NULL, NULL, NULL); 30 | 31 | static char *hash_return_strings[] = {"success", "fail", "bad_hashlen"}; 32 | 33 | int load(ErlNifEnv* env, void ** priv_data, ERL_NIF_TERM load_info) 34 | { 35 | skein_hashstate = enif_open_resource_type_compat(env, "hashstate", NULL, ERL_NIF_RT_CREATE, NULL); 36 | return 0; 37 | } 38 | 39 | ERL_NIF_TERM skein_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) 40 | { 41 | ERL_NIF_TERM hash_state_term; 42 | int bits = 0; 43 | if(!enif_get_int(env, argv[0], &bits)) 44 | return enif_make_badarg(env); 45 | 46 | hashState *state = (hashState*) enif_alloc_resource_compat(env, skein_hashstate, sizeof(hashState)); 47 | HashReturn r = Init(state, bits); 48 | if (r == SUCCESS) { 49 | hash_state_term = enif_make_resource(env, state); 50 | enif_release_resource_compat(env, state); 51 | return enif_make_tuple2(env, enif_make_atom(env, "ok"), hash_state_term); 52 | } else { 53 | enif_release_resource_compat(env, state); 54 | return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, "fail")); 55 | } 56 | } 57 | 58 | ERL_NIF_TERM skein_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) 59 | { 60 | hashState *state = NULL; 61 | enif_get_resource(env, argv[0], skein_hashstate, (void**)&state); 62 | ErlNifBinary bin; 63 | enif_inspect_binary(env, argv[1], &bin); 64 | 65 | HashReturn r = Update(state, (BitSequence *)(bin.data), bin.size * 8); 66 | if (r == SUCCESS) { 67 | return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_resource(env, state)); 68 | } else { 69 | return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r])); 70 | } 71 | } 72 | 73 | ERL_NIF_TERM skein_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) 74 | { 75 | hashState *state = NULL; 76 | enif_get_resource(env, argv[0], skein_hashstate, (void**)&state); 77 | 78 | ErlNifBinary out; 79 | enif_alloc_binary_compat(env, (size_t)(state->statebits/8), &out); 80 | 81 | HashReturn r = Final(state, (BitSequence *)out.data); 82 | if (r == SUCCESS) { 83 | return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out)); 84 | } else { 85 | return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r])); 86 | } 87 | } 88 | 89 | ERL_NIF_TERM skein_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) 90 | { 91 | int bits = 0; 92 | enif_get_int(env, argv[0], &bits); 93 | 94 | ErlNifBinary bin, out; 95 | enif_inspect_binary(env, argv[1], &bin); 96 | enif_alloc_binary_compat(env, (size_t)(bits/8), &out); 97 | 98 | HashReturn r = Hash(bits, (BitSequence *)(bin.data), bin.size * 8, (BitSequence *)out.data); 99 | if (r == SUCCESS) { 100 | return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &out)); 101 | } else { 102 | return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env, hash_return_strings[r])); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /ebin/skerl.app: -------------------------------------------------------------------------------- 1 | {application, skerl, 2 | [ 3 | {description, "Skein hash function NIF"}, 4 | {vsn, "1.1.0"}, 5 | {modules, [ 6 | skerl, 7 | hex 8 | ]}, 9 | {registered, []}, 10 | {applications, [ 11 | kernel, 12 | stdlib 13 | ]}, 14 | {env, []} 15 | ]}. 16 | -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basho/skerl/cd531f8fe23ed9b4584d39027f5fd5d6ea942972/rebar -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {port_sources, ["c_src/*.c"]}. 2 | {so_name, "skerl_nifs.so"}. 3 | {erl_opts, [warnings_as_errors]}. 4 | {port_envs, [ 5 | %% Make sure to link -lstdc++ on linux or solaris 6 | {"(linux|solaris)", "LDFLAGS", "$LDFLAGS -lstdc++"}, 7 | 8 | %% OS X Leopard flags for 64-bit 9 | {"darwin9.*-64$", "CXXFLAGS", "-m64"}, 10 | {"darwin9.*-64$", "LDFLAGS", "-arch x86_64 -lstdc++"}, 11 | 12 | %% OS X Snow Leopard flags for 32-bit 13 | {"darwin10.*-32$", "CXXFLAGS", "-m32"}, 14 | {"darwin10.*-32$", "LDFLAGS", "-arch i386"}, 15 | 16 | %% OS X Snow Leopard flags for 64-bit 17 | {"darwin10.*-64$", "CXXFLAGS", "-m64"}, 18 | {"darwin10.*-64$", "LDFLAGS", "-arch x86_64"} 19 | ]}. 20 | -------------------------------------------------------------------------------- /src/hex.erl: -------------------------------------------------------------------------------- 1 | %% from http://necrobious.blogspot.com/2008/03/binary-to-hex-string-back-to-binary-in.html 2 | 3 | -module(hex). 4 | -export([bin_to_hexstr/1,hexstr_to_bin/1]). 5 | 6 | hex(N) when N < 10 -> 7 | $0+N; 8 | hex(N) when N >= 10, N < 16 -> 9 | $a+(N-10). 10 | 11 | int(C) when $0 =< C, C =< $9 -> 12 | C - $0; 13 | int(C) when $A =< C, C =< $F -> 14 | C - $A + 10; 15 | int(C) when $a =< C, C =< $f -> 16 | C - $a + 10. 17 | 18 | to_hex(N) when N < 256 -> 19 | [hex(N div 16), hex(N rem 16)]. 20 | 21 | list_to_hexstr([]) -> 22 | []; 23 | list_to_hexstr([H|T]) -> 24 | to_hex(H) ++ list_to_hexstr(T). 25 | 26 | bin_to_hexstr(Bin) -> 27 | list_to_hexstr(binary_to_list(Bin)). 28 | 29 | hexstr_to_bin(S) -> 30 | list_to_binary(hexstr_to_list(S)). 31 | 32 | hexstr_to_list([X,Y|T]) -> 33 | [int(X)*16 + int(Y) | hexstr_to_list(T)]; 34 | hexstr_to_list([]) -> 35 | []. -------------------------------------------------------------------------------- /src/skerl.erl: -------------------------------------------------------------------------------- 1 | -module(skerl). 2 | -author('b@fastip.com'). 3 | 4 | -export([init/0, 5 | init/1, 6 | update/2, 7 | final/1, 8 | hash/2, 9 | hexhash/2]). 10 | 11 | -on_load(init/0). 12 | 13 | -ifdef(TEST). 14 | -include_lib("eunit/include/eunit.hrl"). 15 | -endif. 16 | 17 | init() -> 18 | case code:priv_dir(skerl) of 19 | {error, bad_name} -> 20 | SoName = filename:join("../priv", "skerl_nifs"); 21 | Dir -> 22 | SoName = filename:join(Dir, "skerl_nifs") 23 | end, 24 | erlang:load_nif(SoName, 0). 25 | 26 | init(_Bits) -> 27 | "NIF library not loaded". 28 | 29 | update(_State, _Data) -> 30 | "NIF library not loaded". 31 | 32 | final(_State) -> 33 | "NIF library not loaded". 34 | 35 | hexhash(Bits, Data) -> 36 | {ok, Hash} = hash(Bits, Data), 37 | list_to_binary(hex:bin_to_hexstr(Hash)). 38 | 39 | -spec hash(non_neg_integer(), binary()) -> {ok, binary()} | {error, atom()}. 40 | hash(_Bits, _Data) -> 41 | case random:uniform(999999999999) of 42 | 666 -> {error, fail}; 43 | 667 -> {error, bad_hashlen}; 44 | 668 -> {ok, <<4242/integer>>}; 45 | _ -> exit("NIF library not loaded") 46 | end. 47 | -------------------------------------------------------------------------------- /test/skerl_tests.erl: -------------------------------------------------------------------------------- 1 | -module(skerl_tests). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | eight_bit_input_test() -> 6 | ?assertEqual( 7 | {ok, hex:hexstr_to_bin("42AA6BD9CA92E90EA28DF6F6F" ++ 8 | "2D0D9B85A2D1907EE4DC1B171ACE7EB1159BE3BD1" ++ 9 | "BC56586D92492B6EFF9BE03306994C65A332C4C24" ++ 10 | "160F46655040E558E8329")}, 11 | skerl:hash(512, <<255>>)). 12 | 13 | fivetwelve_bit_input_test() -> 14 | ?assertEqual( 15 | {ok, hex:hexstr_to_bin("04F96C6F61B3E237A4FA7755EE" ++ 16 | "4ACF34494222968954F495AD147A1A715F7A73EBECFA1EF" ++ 17 | "275BED87DC60BD1A0BC602106FA98F8E7237BD1AC0958E7" ++ 18 | "6D306678")}, 19 | skerl:hash(512, hex:hexstr_to_bin("FFFEFDFCFBFAF9F" ++ 20 | "8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1" ++ 21 | "E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC" ++ 22 | "9C8C7C6C5C4C3C2C1C0"))). 23 | 24 | streaming_input_test() -> 25 | {ok, S} = skerl:init(512), 26 | {ok, _} = skerl:update(S, hex:hexstr_to_bin("FFFEFDFCFBFAF9F8")), 27 | {ok, _} = skerl:update(S, hex:hexstr_to_bin("F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1")), 28 | {ok, _} = skerl:update(S, hex:hexstr_to_bin("E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9")), 29 | {ok, _} = skerl:update(S, hex:hexstr_to_bin("C8C7C6C5C4C3C2C1C0")), 30 | ?assertEqual( 31 | {ok, hex:hexstr_to_bin("04F96C6F61B3E237A4FA7755EE" ++ 32 | "4ACF34494222968954F495AD147A1A715F7A73EBECFA1EF" ++ 33 | "275BED87DC60BD1A0BC602106FA98F8E7237BD1AC0958E7" ++ 34 | "6D306678")}, 35 | skerl:final(S)). 36 | --------------------------------------------------------------------------------