Back to index

php5  5.3.10
hash_salsa.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Authors: Michael Wallner <mike@php.net>                              |
00016   |          Sara Golemon <pollita@php.net>                              |
00017   +----------------------------------------------------------------------+
00018 */
00019 
00020 /* $Id: hash_salsa.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php_hash.h"
00023 #include "php_hash_salsa.h"
00024 
00025 #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
00026 
00027 /* {{{ Salsa10
00028  
00029  The 64-byte input x to Salsa10 is viewed in little-endian form as 16 integers 
00030  x0, x1, x2, ..., x15 in {0,1,...,2^32-1}. These 16 integers are fed through 
00031  320 invertible modifications, where each modification changes one integer. 
00032  The modifications involve, overall,
00033 
00034     * 10 additions of constants modulo 2^32;
00035     * 320 more additions modulo 2^32;
00036     * 80 ``or'' operations;
00037     * 240 ``xor'' operations; and
00038     * 320 constant-distance rotations. 
00039 
00040  The resulting 16 integers are added to the original x0, x1, x2, ..., x15 
00041  respectively modulo 2^32, producing, in little-endian form, the 64-byte output 
00042  Salsa10(x).
00043  
00044  D.J.Bernstein
00045 */
00046 static void Salsa10(php_hash_uint32 x[16], php_hash_uint32 in[16])
00047 {
00048        int i;
00049        
00050        for (i = 10; i > 0; --i) {
00051               x[ 4] ^= R(x[ 0]+x[12], 6);  x[ 8] ^= R(x[ 4]+x[ 0],17);
00052               x[12] += R(x[ 8]|x[ 4],16);  x[ 0] += R(x[12]^x[ 8], 5);
00053               x[ 9] += R(x[ 5]|x[ 1], 8);  x[13] += R(x[ 9]|x[ 5], 7);
00054               x[ 1] ^= R(x[13]+x[ 9],17);  x[ 5] += R(x[ 1]^x[13],12);
00055               x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] += R(x[14]^x[10],15);
00056               x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],15);
00057               x[ 3] += R(x[15]|x[11],20);  x[ 7] ^= R(x[ 3]+x[15],16);
00058               x[11] += R(x[ 7]^x[ 3], 7);  x[15] += R(x[11]^x[ 7], 8);
00059               x[ 1] += R(x[ 0]|x[ 3], 8)^i;x[ 2] ^= R(x[ 1]+x[ 0],14);
00060               x[ 3] ^= R(x[ 2]+x[ 1], 6);  x[ 0] += R(x[ 3]^x[ 2],18);
00061               x[ 6] += R(x[ 5]^x[ 4], 8);  x[ 7] += R(x[ 6]^x[ 5],12);
00062               x[ 4] += R(x[ 7]|x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],15);
00063               x[11] ^= R(x[10]+x[ 9],18);  x[ 8] += R(x[11]^x[10],11);
00064               x[ 9] ^= R(x[ 8]+x[11], 8);  x[10] += R(x[ 9]|x[ 8], 6);
00065               x[12] += R(x[15]^x[14],17);  x[13] ^= R(x[12]+x[15],15);
00066               x[14] += R(x[13]|x[12], 9);  x[15] += R(x[14]^x[13], 7);
00067        }
00068        for (i = 0; i < 16; ++i) {
00069               x[i] += in[i];
00070        }
00071 }
00072 /* }}} */
00073 
00074 /* {{{ Salsa20
00075  
00076  The 64-byte input x to Salsa20 is viewed in little-endian form as 16 words 
00077  x0, x1, x2, ..., x15 in {0,1,...,2^32-1}. These 16 words are fed through 320 
00078  invertible modifications, where each modification changes one word. The 
00079  resulting 16 words are added to the original x0, x1, x2, ..., x15 respectively 
00080  modulo 2^32, producing, in little-endian form, the 64-byte output Salsa20(x).
00081 
00082  Each modification involves xor'ing into one word a rotated version of the sum 
00083  of two other words modulo 2^32. Thus the 320 modifications involve, overall, 
00084  320 additions, 320 xor's, and 320 rotations. The rotations are all by constant 
00085  distances.
00086 
00087  The entire series of modifications is a series of 10 identical double-rounds. 
00088  Each double-round is a series of 2 rounds. Each round is a set of 4 parallel 
00089  quarter-rounds. Each quarter-round modifies 4 words.
00090  
00091  D.J.Bernstein
00092 */
00093 static void Salsa20(php_hash_uint32 x[16], php_hash_uint32 in[16])
00094 {
00095        int i;
00096        
00097        for (i = 20; i > 0; i -= 2) {
00098               x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
00099               x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);
00100               x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
00101               x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);
00102               x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
00103               x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);
00104               x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
00105               x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);
00106               x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
00107               x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);
00108               x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
00109               x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);
00110               x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
00111               x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);
00112               x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
00113               x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
00114        }
00115        for (i = 0; i < 16; ++i) {
00116               x[i] += in[i];
00117        }
00118 }
00119 /* }}} */
00120 
00121 static inline void SalsaTransform(PHP_SALSA_CTX *context, const unsigned char input[64])
00122 {
00123        php_hash_uint32 i, j, a[16];
00124 
00125 #if 0
00126        fprintf(stderr, "> INPUT: %.*s\n", 64, input);
00127 #endif
00128        
00129        for (i = 0, j = 0; j < 64; i++, j += 4) {
00130               a[i] = ((php_hash_uint32) input[j + 3]) | (((php_hash_uint32) input[j + 2]) << 8) |
00131                      (((php_hash_uint32) input[j + 1]) << 16) | (((php_hash_uint32) input[j]) << 24);
00132        }
00133        
00134        if (!context->init) {
00135               memcpy(context->state, a, sizeof(a));
00136               context->init = 1;
00137        }
00138        
00139        context->Transform(context->state, a);
00140        memset(a, 0, sizeof(a));
00141 }
00142 
00143 PHP_HASH_API void PHP_SALSA10Init(PHP_SALSA_CTX *context)
00144 {
00145        memset(context, 0, sizeof(*context));
00146        context->Transform = Salsa10;
00147 }
00148 
00149 PHP_HASH_API void PHP_SALSA20Init(PHP_SALSA_CTX *context)
00150 {
00151        memset(context, 0, sizeof(*context));
00152        context->Transform = Salsa20;
00153 }
00154 
00155 PHP_HASH_API void PHP_SALSAUpdate(PHP_SALSA_CTX *context, const unsigned char *input, size_t len)
00156 {
00157        if (context->length + len < 64) {
00158               memcpy(&context->buffer[context->length], input, len);
00159               context->length += len;
00160        } else {
00161               size_t i = 0, r = (context->length + len) % 64;
00162               
00163               if (context->length) {
00164                      i = 64 - context->length;
00165                      memcpy(&context->buffer[context->length], input, i);
00166                      SalsaTransform(context, context->buffer);
00167                      memset(context->buffer, 0, 64);
00168               }
00169               
00170               for (; i + 64 <= len; i += 64) {
00171                      SalsaTransform(context, input + i);
00172               }
00173               
00174               memcpy(context->buffer, input + i, r);
00175               context->length = r;
00176        }
00177 }
00178 
00179 PHP_HASH_API void PHP_SALSAFinal(unsigned char digest[64], PHP_SALSA_CTX *context)
00180 {
00181        php_hash_uint32 i, j;
00182        
00183        if (context->length) {
00184               SalsaTransform(context, context->buffer);
00185        }
00186        
00187        for (i = 0, j = 0; j < 64; i++, j += 4) {
00188               digest[j] = (unsigned char) ((context->state[i] >> 24) & 0xff);
00189               digest[j + 1] = (unsigned char) ((context->state[i] >> 16) & 0xff);
00190               digest[j + 2] = (unsigned char) ((context->state[i] >> 8) & 0xff);
00191               digest[j + 3] = (unsigned char) (context->state[i] & 0xff);
00192        }
00193        
00194        memset(context, 0, sizeof(*context));
00195 }
00196 
00197 const php_hash_ops php_hash_salsa10_ops = {
00198        (php_hash_init_func_t) PHP_SALSA10Init,
00199        (php_hash_update_func_t) PHP_SALSAUpdate,
00200        (php_hash_final_func_t) PHP_SALSAFinal,
00201        (php_hash_copy_func_t) php_hash_copy,
00202        64,
00203        64,
00204        sizeof(PHP_SALSA_CTX)
00205 };
00206 
00207 const php_hash_ops php_hash_salsa20_ops = {
00208        (php_hash_init_func_t) PHP_SALSA20Init,
00209        (php_hash_update_func_t) PHP_SALSAUpdate,
00210        (php_hash_final_func_t) PHP_SALSAFinal,
00211        (php_hash_copy_func_t) php_hash_copy,
00212        64,
00213        64,
00214        sizeof(PHP_SALSA_CTX)
00215 };
00216 
00217 /*
00218  * Local variables:
00219  * tab-width: 4
00220  * c-basic-offset: 4
00221  * End:
00222  * vim600: sw=4 ts=4 fdm=marker
00223  * vim<600: sw=4 ts=4
00224  */