1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Michael Wallner <mike@php.net> |
16 : | Sara Golemon <pollita@php.net> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: hash_salsa.c 276986 2009-03-10 23:40:06Z helly $ */
21 :
22 : #include "php_hash.h"
23 : #include "php_hash_salsa.h"
24 :
25 : #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
26 :
27 : /* {{{ Salsa10
28 :
29 : The 64-byte input x to Salsa10 is viewed in little-endian form as 16 integers
30 : x0, x1, x2, ..., x15 in {0,1,...,2^32-1}. These 16 integers are fed through
31 : 320 invertible modifications, where each modification changes one integer.
32 : The modifications involve, overall,
33 :
34 : * 10 additions of constants modulo 2^32;
35 : * 320 more additions modulo 2^32;
36 : * 80 ``or'' operations;
37 : * 240 ``xor'' operations; and
38 : * 320 constant-distance rotations.
39 :
40 : The resulting 16 integers are added to the original x0, x1, x2, ..., x15
41 : respectively modulo 2^32, producing, in little-endian form, the 64-byte output
42 : Salsa10(x).
43 :
44 : D.J.Bernstein
45 : */
46 : static void Salsa10(php_hash_uint32 x[16], php_hash_uint32 in[16])
47 4 : {
48 : int i;
49 :
50 44 : for (i = 10; i > 0; --i) {
51 40 : x[ 4] ^= R(x[ 0]+x[12], 6); x[ 8] ^= R(x[ 4]+x[ 0],17);
52 40 : x[12] += R(x[ 8]|x[ 4],16); x[ 0] += R(x[12]^x[ 8], 5);
53 40 : x[ 9] += R(x[ 5]|x[ 1], 8); x[13] += R(x[ 9]|x[ 5], 7);
54 40 : x[ 1] ^= R(x[13]+x[ 9],17); x[ 5] += R(x[ 1]^x[13],12);
55 40 : x[14] ^= R(x[10]+x[ 6], 7); x[ 2] += R(x[14]^x[10],15);
56 40 : x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],15);
57 40 : x[ 3] += R(x[15]|x[11],20); x[ 7] ^= R(x[ 3]+x[15],16);
58 40 : x[11] += R(x[ 7]^x[ 3], 7); x[15] += R(x[11]^x[ 7], 8);
59 40 : x[ 1] += R(x[ 0]|x[ 3], 8)^i;x[ 2] ^= R(x[ 1]+x[ 0],14);
60 40 : x[ 3] ^= R(x[ 2]+x[ 1], 6); x[ 0] += R(x[ 3]^x[ 2],18);
61 40 : x[ 6] += R(x[ 5]^x[ 4], 8); x[ 7] += R(x[ 6]^x[ 5],12);
62 40 : x[ 4] += R(x[ 7]|x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],15);
63 40 : x[11] ^= R(x[10]+x[ 9],18); x[ 8] += R(x[11]^x[10],11);
64 40 : x[ 9] ^= R(x[ 8]+x[11], 8); x[10] += R(x[ 9]|x[ 8], 6);
65 40 : x[12] += R(x[15]^x[14],17); x[13] ^= R(x[12]+x[15],15);
66 40 : x[14] += R(x[13]|x[12], 9); x[15] += R(x[14]^x[13], 7);
67 : }
68 68 : for (i = 0; i < 16; ++i) {
69 64 : x[i] += in[i];
70 : }
71 4 : }
72 : /* }}} */
73 :
74 : /* {{{ Salsa20
75 :
76 : The 64-byte input x to Salsa20 is viewed in little-endian form as 16 words
77 : x0, x1, x2, ..., x15 in {0,1,...,2^32-1}. These 16 words are fed through 320
78 : invertible modifications, where each modification changes one word. The
79 : resulting 16 words are added to the original x0, x1, x2, ..., x15 respectively
80 : modulo 2^32, producing, in little-endian form, the 64-byte output Salsa20(x).
81 :
82 : Each modification involves xor'ing into one word a rotated version of the sum
83 : of two other words modulo 2^32. Thus the 320 modifications involve, overall,
84 : 320 additions, 320 xor's, and 320 rotations. The rotations are all by constant
85 : distances.
86 :
87 : The entire series of modifications is a series of 10 identical double-rounds.
88 : Each double-round is a series of 2 rounds. Each round is a set of 4 parallel
89 : quarter-rounds. Each quarter-round modifies 4 words.
90 :
91 : D.J.Bernstein
92 : */
93 : static void Salsa20(php_hash_uint32 x[16], php_hash_uint32 in[16])
94 4 : {
95 : int i;
96 :
97 44 : for (i = 20; i > 0; i -= 2) {
98 40 : x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9);
99 40 : x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18);
100 40 : x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9);
101 40 : x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18);
102 40 : x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9);
103 40 : x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18);
104 40 : x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9);
105 40 : x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18);
106 40 : x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9);
107 40 : x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18);
108 40 : x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9);
109 40 : x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18);
110 40 : x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9);
111 40 : x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18);
112 40 : x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9);
113 40 : x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18);
114 : }
115 68 : for (i = 0; i < 16; ++i) {
116 64 : x[i] += in[i];
117 : }
118 4 : }
119 : /* }}} */
120 :
121 : static inline void SalsaTransform(PHP_SALSA_CTX *context, const unsigned char input[64])
122 8 : {
123 : php_hash_uint32 i, j, a[16];
124 :
125 : #if 0
126 : fprintf(stderr, "> INPUT: %.*s\n", 64, input);
127 : #endif
128 :
129 136 : for (i = 0, j = 0; j < 64; i++, j += 4) {
130 128 : a[i] = ((php_hash_uint32) input[j + 3]) | (((php_hash_uint32) input[j + 2]) << 8) |
131 : (((php_hash_uint32) input[j + 1]) << 16) | (((php_hash_uint32) input[j]) << 24);
132 : }
133 :
134 8 : if (!context->init) {
135 8 : memcpy(context->state, a, sizeof(a));
136 8 : context->init = 1;
137 : }
138 :
139 8 : context->Transform(context->state, a);
140 8 : memset(a, 0, sizeof(a));
141 8 : }
142 :
143 : PHP_HASH_API void PHP_SALSA10Init(PHP_SALSA_CTX *context)
144 4 : {
145 4 : memset(context, 0, sizeof(*context));
146 4 : context->Transform = Salsa10;
147 4 : }
148 :
149 : PHP_HASH_API void PHP_SALSA20Init(PHP_SALSA_CTX *context)
150 4 : {
151 4 : memset(context, 0, sizeof(*context));
152 4 : context->Transform = Salsa20;
153 4 : }
154 :
155 : PHP_HASH_API void PHP_SALSAUpdate(PHP_SALSA_CTX *context, const unsigned char *input, size_t len)
156 6 : {
157 6 : if (context->length + len < 64) {
158 6 : memcpy(&context->buffer[context->length], input, len);
159 6 : context->length += len;
160 : } else {
161 0 : size_t i = 0, r = (context->length + len) % 64;
162 :
163 0 : if (context->length) {
164 0 : i = 64 - context->length;
165 0 : memcpy(&context->buffer[context->length], input, i);
166 0 : SalsaTransform(context, context->buffer);
167 0 : memset(context->buffer, 0, 64);
168 : }
169 :
170 0 : for (; i + 64 <= len; i += 64) {
171 0 : SalsaTransform(context, input + i);
172 : }
173 :
174 0 : memcpy(context->buffer, input + i, r);
175 0 : context->length = r;
176 : }
177 6 : }
178 :
179 : PHP_HASH_API void PHP_SALSAFinal(unsigned char digest[64], PHP_SALSA_CTX *context)
180 8 : {
181 : php_hash_uint32 i, j;
182 :
183 8 : if (context->length) {
184 8 : SalsaTransform(context, context->buffer);
185 : }
186 :
187 136 : for (i = 0, j = 0; j < 64; i++, j += 4) {
188 128 : digest[j] = (unsigned char) ((context->state[i] >> 24) & 0xff);
189 128 : digest[j + 1] = (unsigned char) ((context->state[i] >> 16) & 0xff);
190 128 : digest[j + 2] = (unsigned char) ((context->state[i] >> 8) & 0xff);
191 128 : digest[j + 3] = (unsigned char) (context->state[i] & 0xff);
192 : }
193 :
194 8 : memset(context, 0, sizeof(*context));
195 8 : }
196 :
197 : const php_hash_ops php_hash_salsa10_ops = {
198 : (php_hash_init_func_t) PHP_SALSA10Init,
199 : (php_hash_update_func_t) PHP_SALSAUpdate,
200 : (php_hash_final_func_t) PHP_SALSAFinal,
201 : (php_hash_copy_func_t) php_hash_copy,
202 : 64,
203 : 64,
204 : sizeof(PHP_SALSA_CTX)
205 : };
206 :
207 : const php_hash_ops php_hash_salsa20_ops = {
208 : (php_hash_init_func_t) PHP_SALSA20Init,
209 : (php_hash_update_func_t) PHP_SALSAUpdate,
210 : (php_hash_final_func_t) PHP_SALSAFinal,
211 : (php_hash_copy_func_t) php_hash_copy,
212 : 64,
213 : 64,
214 : sizeof(PHP_SALSA_CTX)
215 : };
216 :
217 : /*
218 : * Local variables:
219 : * tab-width: 4
220 : * c-basic-offset: 4
221 : * End:
222 : * vim600: sw=4 ts=4 fdm=marker
223 : * vim<600: sw=4 ts=4
224 : */
|