pcompress/crypto/xsalsa20/hsalsa_core.c
2013-03-07 20:26:48 +05:30

132 lines
3.5 KiB
C

/*
* This file is a part of Pcompress, a chunked parallel multi-
* algorithm lossless compression and decompression program.
*
* Copyright (C) 2012-2013 Moinak Ghosh. All rights reserved.
* Use is subject to license terms.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
* moinakg@belenix.org, http://moinakg.wordpress.com/
*/
/*
version 20080912
D. J. Bernstein
Public domain.
*/
#include <inttypes.h>
#include <utils.h>
#define ROUNDS 20
static uint32_t
rotate(uint32_t u,int c)
{
return (u << c) | (u >> (32 - c));
}
static uint32_t
load_littleendian(const unsigned char *x)
{
return
(uint32_t) (x[0]) \
| (((uint32_t) (x[1])) << 8) \
| (((uint32_t) (x[2])) << 16) \
| (((uint32_t) (x[3])) << 24)
;
}
static void
store_littleendian(unsigned char *x, uint32_t u)
{
x[0] = u; u >>= 8;
x[1] = u; u >>= 8;
x[2] = u; u >>= 8;
x[3] = u;
}
int
crypto_core_hsalsa20(unsigned char *out,
const unsigned char *in,
const unsigned char *k,
const unsigned char *c)
{
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
int i;
x0 = load_littleendian(c + 0);
x1 = load_littleendian(k + 0);
x2 = load_littleendian(k + 4);
x3 = load_littleendian(k + 8);
x4 = load_littleendian(k + 12);
x5 = load_littleendian(c + 4);
x6 = load_littleendian(in + 0);
x7 = load_littleendian(in + 4);
x8 = load_littleendian(in + 8);
x9 = load_littleendian(in + 12);
x10 = load_littleendian(c + 8);
x11 = load_littleendian(k + 16);
x12 = load_littleendian(k + 20);
x13 = load_littleendian(k + 24);
x14 = load_littleendian(k + 28);
x15 = load_littleendian(c + 12);
for (i = ROUNDS;i > 0;i -= 2) {
x4 ^= rotate( x0+x12, 7);
x8 ^= rotate( x4+ x0, 9);
x12 ^= rotate( x8+ x4,13);
x0 ^= rotate(x12+ x8,18);
x9 ^= rotate( x5+ x1, 7);
x13 ^= rotate( x9+ x5, 9);
x1 ^= rotate(x13+ x9,13);
x5 ^= rotate( x1+x13,18);
x14 ^= rotate(x10+ x6, 7);
x2 ^= rotate(x14+x10, 9);
x6 ^= rotate( x2+x14,13);
x10 ^= rotate( x6+ x2,18);
x3 ^= rotate(x15+x11, 7);
x7 ^= rotate( x3+x15, 9);
x11 ^= rotate( x7+ x3,13);
x15 ^= rotate(x11+ x7,18);
x1 ^= rotate( x0+ x3, 7);
x2 ^= rotate( x1+ x0, 9);
x3 ^= rotate( x2+ x1,13);
x0 ^= rotate( x3+ x2,18);
x6 ^= rotate( x5+ x4, 7);
x7 ^= rotate( x6+ x5, 9);
x4 ^= rotate( x7+ x6,13);
x5 ^= rotate( x4+ x7,18);
x11 ^= rotate(x10+ x9, 7);
x8 ^= rotate(x11+x10, 9);
x9 ^= rotate( x8+x11,13);
x10 ^= rotate( x9+ x8,18);
x12 ^= rotate(x15+x14, 7);
x13 ^= rotate(x12+x15, 9);
x14 ^= rotate(x13+x12,13);
x15 ^= rotate(x14+x13,18);
}
store_littleendian(out + 0,x0);
store_littleendian(out + 4,x5);
store_littleendian(out + 8,x10);
store_littleendian(out + 12,x15);
store_littleendian(out + 16,x6);
store_littleendian(out + 20,x7);
store_littleendian(out + 24,x8);
store_littleendian(out + 28,x9);
return 0;
}