/* * Copyright (C) 2001-2006 Jacek Sieka, arnetheduck on gmail point com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* DC++ protocl utls for GHC Copyright (C) 2009 Nikolay Orlyuk (virkony _at_ gmail _dot_ com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "tiger.h" #if defined(__GNUC__) #define _ULL(c) ((uint64_t)(c ## ULL)) #else #define _ULL(c) (c ## ui64) #endif #ifdef _WIN32 #if defined(_M_X64) #define TIGER_ARCH64 #endif #if !(defined(_M_IX86) || defined(_M_X64)) #define TIGER_BIG_ENDIAN #endif #else /* _WIN32 */ #if defined(__x86_64__) || defined(__alpha) #define TIGER_ARCH64 #endif #if !(defined(__i386__) || defined(__x86_64__) || defined(__alpha)) #define TIGER_BIG_ENDIAN #endif #endif /* _WIN32 */ #define PASSES 3 #define t1 (table) #define t2 (table+256) #define t3 (table+256*2) #define t4 (table+256*3) #define save_abc \ aa = a; \ bb = b; \ cc = c; #ifdef TIGER_ARCH64 #define round(a,b,c,x,mul) \ c ^= x; \ a -= t1[((c)>>(0*8))&0xFF] ^ t2[((c)>>(2*8))&0xFF] ^ \ t3[((c)>>(4*8))&0xFF] ^ t4[((c)>>(6*8))&0xFF] ; \ b += t4[((c)>>(1*8))&0xFF] ^ t3[((c)>>(3*8))&0xFF] ^ \ t2[((c)>>(5*8))&0xFF] ^ t1[((c)>>(7*8))&0xFF] ; \ b *= mul; #else #define round(a,b,c,x,mul) \ c ^= x; \ a -= t1[(uint8_t)(c)] ^ \ t2[(uint8_t)(((uint32_t)(c))>>(2*8))] ^ \ t3[(uint8_t)((c)>>(4*8))] ^ \ t4[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(2*8))] ; \ b += t4[(uint8_t)(((uint32_t)(c))>>(1*8))] ^ \ t3[(uint8_t)(((uint32_t)(c))>>(3*8))] ^ \ t2[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(1*8))] ^ \ t1[(uint8_t)(((uint32_t)((c)>>(4*8)))>>(3*8))]; \ b *= mul; #endif #define pass(a,b,c,mul) \ round(a,b,c,x0,mul) \ round(b,c,a,x1,mul) \ round(c,a,b,x2,mul) \ round(a,b,c,x3,mul) \ round(b,c,a,x4,mul) \ round(c,a,b,x5,mul) \ round(a,b,c,x6,mul) \ round(b,c,a,x7,mul) #define key_schedule \ x0 -= x7 ^ _ULL(0xA5A5A5A5A5A5A5A5); \ x1 ^= x0; \ x2 += x1; \ x3 -= x2 ^ ((~x1)<<19); \ x4 ^= x3; \ x5 += x4; \ x6 -= x5 ^ ((~x4)>>23); \ x7 ^= x6; \ x0 += x7; \ x1 -= x0 ^ ((~x7)<<19); \ x2 ^= x1; \ x3 += x2; \ x4 -= x3 ^ ((~x2)>>23); \ x5 ^= x4; \ x6 += x5; \ x7 -= x6 ^ _ULL(0x0123456789ABCDEF); #define feedforward \ a ^= aa; \ b -= bb; \ c += cc; #ifdef TIGER_ARCH64 #define compress \ save_abc \ pass(a,b,c,5) \ key_schedule \ pass(c,a,b,7) \ key_schedule \ pass(b,c,a,9) \ for(pass_no=3; pass_nobytes = _ULL(0), ctx->a = INIT_A, ctx->b = INIT_B, ctx->c = INIT_C; } void tiger_free(tiger_context *ctx) { return free(ctx); } static inline const uint64_t bswap_64(const uint64_t x) { /* [0,8,16,24,32,40,48,56] */ return ( ((x & _ULL(0xff00000000000000)) >> 56) | ((x & _ULL(0x00ff000000000000)) >> 40) | ((x & _ULL(0x0000ff0000000000)) >> 24) | ((x & _ULL(0x000000ff00000000)) >> 8) | ((x & _ULL(0x00000000ff000000)) << 8) | ((x & _ULL(0x0000000000ff0000)) << 24) | ((x & _ULL(0x000000000000ff00)) << 40) | ((x & _ULL(0x00000000000000ff)) << 56) ); } void tiger_feed(tiger_context *ctx, const void *block, size_t bytes_count) { const size_t pending_bytes = ctx->bytes % TIGER_BLOCK_SIZE; #ifdef TIGER_BIG_ENDIAN size_t i; #endif //assert( !(bits_count % 8) || !"implemented yet" ); if ((pending_bytes > 0) || (bytes_count < TIGER_BLOCK_SIZE)) { const size_t align_bytes = TIGER_BLOCK_SIZE-pending_bytes; if (align_bytes > bytes_count) { memcpy(ctx->pending.bytes + pending_bytes, block, bytes_count); ctx->bytes += bytes_count; return; } memcpy(ctx->pending.bytes + pending_bytes, block, align_bytes); ctx->bytes += align_bytes, block = (const uint8_t*)block + align_bytes, bytes_count -= align_bytes; #ifdef TIGER_BIG_ENDIAN for(i=0;ipending.words[i] = bswap_64(ctx->pending.words[i]); #endif tiger_compress_macro(ctx->pending.words, ctx->a, ctx->b, ctx->c); } ctx->bytes += bytes_count; while( bytes_count >= TIGER_BLOCK_SIZE ) { #ifdef TIGER_BIG_ENDIAN for(i=0;ipending.bytes[i^7] = ((const uint8_t*)block)[i]; tiger_compress_macro(ctx->pending.words, ctx->a, ctx->b, ctx->c); #else tiger_compress_macro((const uint64_t*)block, ctx->a, ctx->b, ctx->c); #endif block = (const uint8_t*)block + TIGER_BLOCK_SIZE, bytes_count -= TIGER_BLOCK_SIZE; } memcpy(ctx->pending.bytes, block, bytes_count); } void tiger_finalize(tiger_context *ctx, void *hash) { const size_t pending_bytes = ctx->bytes % TIGER_BLOCK_SIZE; uint64_t * const res = hash; res[0] = ctx->a, res[1] = ctx->b, res[2] = ctx->c; #ifndef TIGER_BIG_ENDIAN /* inplace */ if( (pending_bytes + 1 + 8) < TIGER_BLOCK_SIZE) { ctx->pending.bytes[pending_bytes] = 0x01; memset(ctx->pending.bytes + pending_bytes + 1, 0, TIGER_BLOCK_SIZE - pending_bytes - 1); ctx->pending.words[7] = ctx->bytes * 8; tiger_compress_macro(ctx->pending.words, res[0], res[1], res[2]); } else #endif { union { uint64_t words[TIGER_BLOCK_WSIZE]; uint8_t bytes[TIGER_BLOCK_SIZE]; } buf; #ifdef TIGER_BIG_ENDIAN size_t i; #endif memcpy(buf.bytes, ctx->pending.bytes, pending_bytes); buf.bytes[pending_bytes] = 0x01; memset(buf.bytes + pending_bytes + 1, 0, TIGER_BLOCK_SIZE - pending_bytes - 1); if ((pending_bytes + 1 + 8) > TIGER_BLOCK_SIZE) { #ifdef TIGER_BIG_ENDIAN for(i=0;ibytes*8; #ifdef TIGER_BIG_ENDIAN for(i=0;i