Upload UI
[lsnes.git] / src / library / skein.cpp
blobcd48acd13ec44853dafb84fca01097ad8296311f
1 #include <cstdint>
2 #include <cstring>
3 #include "skein.hpp"
4 #include <iostream>
5 #include <stdexcept>
6 #include <iomanip>
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)
16 std::cerr << prefix;
17 for(size_t i = 0; i < e; i++) {
18 std::cerr << std::hex << std::setw(16) << std::setfill('0') << a[i];
19 if(i < e - 1)
20 std::cerr << ", ";
22 std::cerr << std::endl;
25 static void show_array(const char* prefix, const uint8_t* a, size_t e)
27 std::cerr << prefix;
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);
40 #endif
41 skein256_compress(a, b, c, d);
42 #ifdef TEST_SKEIN_CODE
43 show_array("Out: ", a, 4);
44 #endif
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);
53 #endif
54 skein512_compress(a, b, c, d);
55 #ifdef TEST_SKEIN_CODE
56 show_array("Out: ", a, 8);
57 #endif
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);
66 #endif
67 skein1024_compress(a, b, c, d);
68 #ifdef TEST_SKEIN_CODE
69 show_array("Out: ", a, 16);
70 #endif
73 skein_hash::skein_hash(skein_hash::variant v, uint64_t _outbits)
75 memset(chain, 0, sizeof(chain));
76 memset(buffer, 0, sizeof(buffer));
77 switch(v) {
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");
83 bufferfill = 0;
84 data_low = 0;
85 data_high = 0;
86 outbits = _outbits;
87 last_type = -1;
90 void skein_hash::configure()
92 uint64_t config[16] = {0x133414853ULL,outbits};
93 uint64_t tweak[2] = {32,0xC400000000000000ULL};
94 uint64_t iv[16];
95 compress(iv, config, chain, tweak);
96 memcpy(chain, iv, fullbuffer);
97 last_type = 4;
100 void skein_hash::typechange(uint8_t newtype)
102 if(last_type != newtype) {
103 //Type change.
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)
109 configure();
110 //3) If changing over MESSAGE, flush even if empty.
111 if(last_type < 48 && newtype > 48) {
112 last_type = newtype;
113 data_low = 0;
114 data_high = 0;
115 flush_buffer(48, true);
117 last_type = newtype;
118 data_low = 0;
119 data_high = 0;
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");
127 if(type < last_type)
128 throw std::runtime_error("Data types in wrong order");
129 while(datalen > 0) {
130 typechange(type);
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;
138 } else {
139 memcpy(buffer + bufferfill, data, datalen);
140 data += datalen;
141 bufferfill += datalen;
142 datalen = 0;
147 void skein_hash::flush_buffer(uint8_t type, bool final)
149 uint64_t _buffer[16];
150 uint64_t _buffer2[16];
151 uint64_t tweak[2];
152 tweak[0] = data_low + bufferfill;
153 tweak[1] = data_high;
154 if(tweak[0] < data_low)
155 tweak[1]++;
156 tweak[1] += ((uint64_t)type << 56);
157 if(!data_low && !data_high)
158 tweak[1] += (1ULL << 62);
159 if(final)
160 tweak[1] += (1ULL << 63);
161 #ifdef ARCH_IS_I386
162 memcpy(_buffer, buffer, fullbuffer);
163 #else
164 for(unsigned i = 0; i < (fullbuffer>>3); i++)
165 _buffer[i]=0;
166 for(unsigned i = 0; i < fullbuffer; i++)
167 _buffer[i>>3]|=((uint64_t)buffer[i] << ((i&7)<<3));
168 #endif
169 compress(_buffer2, _buffer, chain, tweak);
170 memcpy(chain, _buffer2, fullbuffer);
171 data_low += bufferfill;
172 if(data_low < bufferfill)
173 data_high++;
174 bufferfill = 0;
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};
183 uint64_t out[16];
184 uint64_t tweak[2] = {8,0xFF00000000000000ULL};
185 uint64_t offset = 0;
186 for(uint64_t i = 0; i < outbits; i += (fullbuffer<<3)) {
187 compress(out, zeroes, chain, tweak);
188 zeroes[0]++;
189 uint64_t fullbytes = (outbits - i) >> 3;
190 if(fullbytes > fullbuffer) fullbytes = fullbuffer;
191 #ifdef ARCH_IS_I386
192 memcpy(output + offset, out, fullbytes);
193 #else
194 for(unsigned i = 0; i < fullbytes; i++)
195 output[offset + i] = (out[i>>3] >> ((i&7)<<3));
196 #endif
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
206 #define SKEIN_DEBUG
207 #include "skein.h"
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;
216 uint8_t out[128];
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);
220 ctx.read(out);
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);
227 return 0;
230 int main()
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};
236 uint8_t out[128];
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);
240 ctx.write(buf, 2);
241 ctx.read(out);
242 show_array("", out, 32);
245 #endif