7 #include "skein512c.inc"
8 #include "arch-detect.hpp"
10 //Jerry Solinas was not here.
12 static uint8_t bitmasks
[] = {0, 128, 192, 224, 240, 248, 252, 254, 255};
14 static void show_array(const char* prefix
, const uint64_t* a
, size_t e
)
17 for(size_t i
= 0; i
< e
; i
++) {
18 std::cerr
<< std::hex
<< std::setw(16) << std::setfill('0') << a
[i
];
22 std::cerr
<< std::endl
;
25 static void show_array(const char* prefix
, const uint8_t* a
, size_t e
)
28 for(size_t i
= 0; i
< e
; i
++) {
29 std::cerr
<< std::hex
<< std::setw(2) << std::setfill('0') << (int)a
[i
];
31 std::cerr
<< std::endl
;
34 inline static void _skein256_compress(uint64_t* a
, const uint64_t* b
, const uint64_t* c
, const uint64_t* d
)
36 #ifdef TEST_SKEIN_CODE
37 show_array("Key: ", c
, 4);
38 show_array("Data: ", b
, 4);
39 show_array("Tweak: ", d
, 2);
41 skein256_compress(a
, b
, c
, d
);
42 #ifdef TEST_SKEIN_CODE
43 show_array("Out: ", a
, 4);
47 inline static void _skein512_compress(uint64_t* a
, const uint64_t* b
, const uint64_t* c
, const uint64_t* d
)
49 #ifdef TEST_SKEIN_CODE
50 show_array("Key: ", c
, 8);
51 show_array("Data: ", b
, 8);
52 show_array("Tweak: ", d
, 2);
54 skein512_compress(a
, b
, c
, d
);
55 #ifdef TEST_SKEIN_CODE
56 show_array("Out: ", a
, 8);
60 inline static void _skein1024_compress(uint64_t* a
, const uint64_t* b
, const uint64_t* c
, const uint64_t* d
)
62 #ifdef TEST_SKEIN_CODE
63 show_array("Key: ", c
, 16);
64 show_array("Data: ", b
, 16);
65 show_array("Tweak: ", d
, 2);
67 skein1024_compress(a
, b
, c
, d
);
68 #ifdef TEST_SKEIN_CODE
69 show_array("Out: ", a
, 16);
73 skein_hash::skein_hash(skein_hash::variant v
, uint64_t _outbits
)
75 memset(chain
, 0, sizeof(chain
));
76 memset(buffer
, 0, sizeof(buffer
));
78 case PIPE_256
: compress
= _skein256_compress
; fullbuffer
= 32; break;
79 case PIPE_512
: compress
= _skein512_compress
; fullbuffer
= 64; break;
80 case PIPE_1024
: compress
= _skein1024_compress
; fullbuffer
= 128; break;
81 default: throw std::runtime_error("Invalid Skein variant");
90 void skein_hash::configure()
92 uint64_t config
[16] = {0x133414853ULL
,outbits
};
93 uint64_t tweak
[2] = {32,0xC400000000000000ULL
};
95 compress(iv
, config
, chain
, tweak
);
96 memcpy(chain
, iv
, fullbuffer
);
100 void skein_hash::typechange(uint8_t newtype
)
102 if(last_type
!= newtype
) {
104 //1) If changing from any other last type except NONE or CONFIG, flush.
105 if(last_type
>= 0 && last_type
!= 4)
106 flush_buffer(last_type
, true);
107 //2) If changing over CONFIG, configure the hash.
108 if(last_type
< 4 && newtype
> 4)
110 //3) If changing over MESSAGE, flush even if empty.
111 if(last_type
< 48 && newtype
> 48) {
115 flush_buffer(48, true);
123 void skein_hash::write(const uint8_t* data
, size_t datalen
, skein_hash::datatype type
)
125 if(type
< 0 || type
== 4 || type
> 62)
126 throw std::runtime_error("Invalid data type to write");
128 throw std::runtime_error("Data types in wrong order");
131 if(bufferfill
== fullbuffer
)
132 flush_buffer(type
, false);
133 if(datalen
>= fullbuffer
- bufferfill
) {
134 memcpy(buffer
+ bufferfill
, data
, fullbuffer
- bufferfill
);
135 data
+= (fullbuffer
- bufferfill
);
136 datalen
-= (fullbuffer
- bufferfill
);
137 bufferfill
= fullbuffer
;
139 memcpy(buffer
+ bufferfill
, data
, datalen
);
141 bufferfill
+= datalen
;
147 void skein_hash::flush_buffer(uint8_t type
, bool final
)
149 uint64_t _buffer
[16];
150 uint64_t _buffer2
[16];
152 tweak
[0] = data_low
+ bufferfill
;
153 tweak
[1] = data_high
;
154 if(tweak
[0] < data_low
)
156 tweak
[1] += ((uint64_t)type
<< 56);
157 if(!data_low
&& !data_high
)
158 tweak
[1] += (1ULL << 62);
160 tweak
[1] += (1ULL << 63);
162 memcpy(_buffer
, buffer
, fullbuffer
);
164 for(unsigned i
= 0; i
< (fullbuffer
>>3); i
++)
166 for(unsigned i
= 0; i
< fullbuffer
; i
++)
167 _buffer
[i
>>3]|=((uint64_t)buffer
[i
] << ((i
&7)<<3));
169 compress(_buffer2
, _buffer
, chain
, tweak
);
170 memcpy(chain
, _buffer2
, fullbuffer
);
171 data_low
+= bufferfill
;
172 if(data_low
< bufferfill
)
175 memset(buffer
, 0, fullbuffer
);
178 void skein_hash::read(uint8_t* output
)
180 typechange(63); //Switch to output.
181 //The final one is special.
182 uint64_t zeroes
[16] = {0};
184 uint64_t tweak
[2] = {8,0xFF00000000000000ULL
};
186 for(uint64_t i
= 0; i
< outbits
; i
+= (fullbuffer
<<3)) {
187 compress(out
, zeroes
, chain
, tweak
);
189 uint64_t fullbytes
= (outbits
- i
) >> 3;
190 if(fullbytes
> fullbuffer
) fullbytes
= fullbuffer
;
192 memcpy(output
+ offset
, out
, fullbytes
);
194 for(unsigned i
= 0; i
< fullbytes
; i
++)
195 output
[offset
+ i
] = (out
[i
>>3] >> ((i
&7)<<3));
197 if(fullbytes
< fullbuffer
&& i
+ 8 * fullbytes
< outbits
) {
198 output
[offset
+ fullbytes
] = (out
[fullbytes
>>3] >> ((fullbytes
&7)<<3));
199 output
[offset
+ fullbytes
] &= bitmasks
[outbits
&7];
201 offset
+= fullbuffer
;
205 #ifdef TEST_SKEIN_CODE
208 #include "skein_debug.h"
212 int main(int argc
, char** argv
)
215 //skein_DebugFlag = SKEIN_DEBUG_STATE | SKEIN_DEBUG_TWEAK | SKEIN_DEBUG_INPUT_64;
217 skein_hash ctx(skein_hash::PIPE_512, 256);
218 ctx.write((uint8_t*)argv[1], strlen(argv[1]), skein_hash::T_KEY);
219 ctx.write((uint8_t*)argv[2], strlen(argv[2]), skein_hash::T_MESSAGE);
221 show_array("New: ", out, 32);
222 Skein_512_Ctxt_t ctx2;
223 Skein_512_InitExt(&ctx2, 256, SKEIN_CFG_TREE_INFO_SEQUENTIAL, (uint8_t*)argv[1], strlen(argv[1]));
224 Skein_512_Update(&ctx2, (uint8_t*)argv[2], strlen(argv[2]));
225 Skein_512_Final(&ctx2, out);
226 show_array("Ref: ", out, 32);
234 uint8_t buf
[129] = {0xFF,0xFE,0xFD,0xFC,0xFB,0xFA,0xF9,0xF8,0xF7};
235 uint8_t key
[135] = {0x05,0x04,0x46,0x22,0x26,0x35,0x63,0x26,0xFF};
237 skein_hash
ctx(skein_hash::PIPE_256
, 256);
238 ctx
.write(key
, sizeof(key
), skein_hash::T_KEY
);
239 ctx
.write(key
, sizeof(key
), skein_hash::T_NONCE
);
242 show_array("", out
, 32);