Annotation of embedaddon/strongswan/src/libstrongswan/plugins/chapoly/chapoly_drv_ssse3.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2015 Martin Willi
                      3:  * Copyright (C) 2015 revosec AG
                      4:  *
                      5:  * Based on public domain code by Andrew Moon and Daniel J. Bernstein.
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or modify it
                      8:  * under the terms of the GNU General Public License as published by the
                      9:  * Free Software Foundation; either version 2 of the License, or (at your
                     10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful, but
                     13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     15:  * for more details.
                     16:  */
                     17: 
                     18: #include "chapoly_drv_ssse3.h"
                     19: 
                     20: #ifdef __SSSE3__
                     21: 
                     22: #include <utils/cpu_feature.h>
                     23: 
                     24: #include <tmmintrin.h>
                     25: 
                     26: #define CHACHA_DOUBLEROUNDS 10
                     27: 
                     28: typedef struct private_chapoly_drv_ssse3_t private_chapoly_drv_ssse3_t;
                     29: 
                     30: /**
                     31:  * Private data of an chapoly_drv_ssse3_t object.
                     32:  */
                     33: struct private_chapoly_drv_ssse3_t {
                     34: 
                     35:        /**
                     36:         * Public chapoly_drv_ssse3_t interface.
                     37:         */
                     38:        chapoly_drv_t public;
                     39: 
                     40:        /**
                     41:         * ChaCha20 state matrix, as 128-bit vectors
                     42:         */
                     43:        __m128i m[4];
                     44: 
                     45:        /**
                     46:         * Poly1305 update key
                     47:         */
                     48:        uint32_t r[5];
                     49: 
                     50:        /**
                     51:         * Poly1305 update key r^2
                     52:         */
                     53:        uint32_t u[5];
                     54: 
                     55:        /**
                     56:         * Poly1305 state
                     57:         */
                     58:        uint32_t h[5];
                     59: 
                     60:        /**
                     61:         * Poly1305 finalize key
                     62:         */
                     63:        uint32_t s[4];
                     64: };
                     65: 
                     66: /**
                     67:  * Read a 32-bit integer from an unaligned address
                     68:  */
                     69: static inline uint32_t ru32(void *p)
                     70: {
                     71:        uint32_t ret;
                     72: 
                     73:        memcpy(&ret, p, sizeof(ret));
                     74:        return ret;
                     75: }
                     76: 
                     77: /**
                     78:  * Write a 32-bit word to an unaligned address
                     79:  */
                     80: static inline void wu32(void *p, uint32_t v)
                     81: {
                     82:        memcpy(p, &v, sizeof(v));
                     83: }
                     84: 
                     85: /**
                     86:  * Shift a 64-bit unsigned integer v right by n bits, clamp to 32 bit
                     87: */
                     88: static inline uint32_t sr(uint64_t v, u_char n)
                     89: {
                     90:        return v >> n;
                     91: }
                     92: 
                     93: /**
                     94:  * AND two values, using a native integer size >= sizeof(uint32_t)
                     95:  */
                     96: static inline u_long and(u_long v, u_long mask)
                     97: {
                     98:        return v & mask;
                     99: }
                    100: 
                    101: /**
                    102:  * r = shuffle(a ^ b, s)
                    103:  */
                    104: static inline __m128i sfflxor32(__m128i a, __m128i b, __m128i s)
                    105: {
                    106:        return _mm_shuffle_epi8(_mm_xor_si128(a, b), s);
                    107: }
                    108: 
                    109: /**
                    110:  * r = rotl32(a ^ b, r)
                    111:  */
                    112: static inline __m128i rotlxor32(__m128i a, __m128i b, u_char r)
                    113: {
                    114:        a = _mm_xor_si128(a, b);
                    115:        return _mm_or_si128(_mm_slli_epi32(a, r), _mm_srli_epi32(a, 32 - r));
                    116: }
                    117: 
                    118: /**
                    119:  * XOR a Chacha20 keystream block into data, increment counter
                    120:  */
                    121: static void chacha_block_xor(private_chapoly_drv_ssse3_t *this, void *data)
                    122: {
                    123:        __m128i x0, x1, x2, x3, r8, r16, *out = data;
                    124:        u_int i;
                    125: 
                    126:        r8  = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
                    127:        r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
                    128: 
                    129:        x0 = this->m[0];
                    130:        x1 = this->m[1];
                    131:        x2 = this->m[2];
                    132:        x3 = this->m[3];
                    133: 
                    134:        for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
                    135:        {
                    136:                x0 = _mm_add_epi32(x0, x1);
                    137:                x3 = sfflxor32(x3, x0, r16);
                    138: 
                    139:                x2 = _mm_add_epi32(x2, x3);
                    140:                x1 = rotlxor32(x1, x2, 12);
                    141: 
                    142:                x0 = _mm_add_epi32(x0, x1);
                    143:                x3 = sfflxor32(x3, x0, r8);
                    144: 
                    145:                x2 = _mm_add_epi32(x2, x3);
                    146:                x1 = rotlxor32(x1, x2, 7);
                    147: 
                    148:                x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(0, 3, 2, 1));
                    149:                x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
                    150:                x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(2, 1, 0, 3));
                    151: 
                    152:                x0 = _mm_add_epi32(x0, x1);
                    153:                x3 = sfflxor32(x3, x0, r16);
                    154: 
                    155:                x2 = _mm_add_epi32(x2, x3);
                    156:                x1 = rotlxor32(x1, x2, 12);
                    157: 
                    158:                x0 = _mm_add_epi32(x0, x1);
                    159:                x3 = sfflxor32(x3, x0, r8);
                    160: 
                    161:                x2 = _mm_add_epi32(x2, x3);
                    162:                x1 = rotlxor32(x1, x2, 7);
                    163: 
                    164:                x1 = _mm_shuffle_epi32(x1, _MM_SHUFFLE(2, 1, 0, 3));
                    165:                x2 = _mm_shuffle_epi32(x2, _MM_SHUFFLE(1, 0, 3, 2));
                    166:                x3 = _mm_shuffle_epi32(x3, _MM_SHUFFLE(0, 3, 2, 1));
                    167:        }
                    168: 
                    169:        x0 = _mm_add_epi32(x0, this->m[0]);
                    170:        x1 = _mm_add_epi32(x1, this->m[1]);
                    171:        x2 = _mm_add_epi32(x2, this->m[2]);
                    172:        x3 = _mm_add_epi32(x3, this->m[3]);
                    173:        x0 = _mm_xor_si128(x0, _mm_loadu_si128(out + 0));
                    174:        x1 = _mm_xor_si128(x1, _mm_loadu_si128(out + 1));
                    175:        x2 = _mm_xor_si128(x2, _mm_loadu_si128(out + 2));
                    176:        x3 = _mm_xor_si128(x3, _mm_loadu_si128(out + 3));
                    177:        _mm_storeu_si128(out + 0, x0);
                    178:        _mm_storeu_si128(out + 1, x1);
                    179:        _mm_storeu_si128(out + 2, x2);
                    180:        _mm_storeu_si128(out + 3, x3);
                    181: 
                    182:        this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 1));
                    183: }
                    184: 
                    185: /**
                    186:  * XOR four Chacha20 keystream blocks into data, increment counter
                    187:  */
                    188: static void chacha_4block_xor(private_chapoly_drv_ssse3_t *this, void *data)
                    189: {
                    190:        __m128i x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf;
                    191:        __m128i r8, r16, ctrinc, t, *out = data;
                    192:        uint32_t *m = (uint32_t*)this->m;
                    193:        u_int i;
                    194: 
                    195:        r8  = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
                    196:        r16 = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
                    197:        ctrinc = _mm_set_epi32(3, 2, 1, 0);
                    198: 
                    199:        x0 = _mm_set1_epi32(m[ 0]);
                    200:        x1 = _mm_set1_epi32(m[ 1]);
                    201:        x2 = _mm_set1_epi32(m[ 2]);
                    202:        x3 = _mm_set1_epi32(m[ 3]);
                    203:        x4 = _mm_set1_epi32(m[ 4]);
                    204:        x5 = _mm_set1_epi32(m[ 5]);
                    205:        x6 = _mm_set1_epi32(m[ 6]);
                    206:        x7 = _mm_set1_epi32(m[ 7]);
                    207:        x8 = _mm_set1_epi32(m[ 8]);
                    208:        x9 = _mm_set1_epi32(m[ 9]);
                    209:        xa = _mm_set1_epi32(m[10]);
                    210:        xb = _mm_set1_epi32(m[11]);
                    211:        xc = _mm_set1_epi32(m[12]);
                    212:        xd = _mm_set1_epi32(m[13]);
                    213:        xe = _mm_set1_epi32(m[14]);
                    214:        xf = _mm_set1_epi32(m[15]);
                    215: 
                    216:        xc = _mm_add_epi32(xc, ctrinc);
                    217: 
                    218:        for (i = 0 ; i < CHACHA_DOUBLEROUNDS; i++)
                    219:        {
                    220:                x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r16);
                    221:                x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r16);
                    222:                x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r16);
                    223:                x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r16);
                    224: 
                    225:                x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 12);
                    226:                x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 12);
                    227:                xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 12);
                    228:                xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 12);
                    229: 
                    230:                x0 = _mm_add_epi32(x0, x4); xc = sfflxor32(xc, x0, r8);
                    231:                x1 = _mm_add_epi32(x1, x5); xd = sfflxor32(xd, x1, r8);
                    232:                x2 = _mm_add_epi32(x2, x6); xe = sfflxor32(xe, x2, r8);
                    233:                x3 = _mm_add_epi32(x3, x7); xf = sfflxor32(xf, x3, r8);
                    234: 
                    235:                x8 = _mm_add_epi32(x8, xc); x4 = rotlxor32(x4, x8, 7);
                    236:                x9 = _mm_add_epi32(x9, xd); x5 = rotlxor32(x5, x9, 7);
                    237:                xa = _mm_add_epi32(xa, xe); x6 = rotlxor32(x6, xa, 7);
                    238:                xb = _mm_add_epi32(xb, xf); x7 = rotlxor32(x7, xb, 7);
                    239: 
                    240:                x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r16);
                    241:                x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r16);
                    242:                x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r16);
                    243:                x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r16);
                    244: 
                    245:                xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 12);
                    246:                xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 12);
                    247:                x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 12);
                    248:                x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 12);
                    249: 
                    250:                x0 = _mm_add_epi32(x0, x5); xf = sfflxor32(xf, x0, r8);
                    251:                x1 = _mm_add_epi32(x1, x6); xc = sfflxor32(xc, x1, r8);
                    252:                x2 = _mm_add_epi32(x2, x7); xd = sfflxor32(xd, x2, r8);
                    253:                x3 = _mm_add_epi32(x3, x4); xe = sfflxor32(xe, x3, r8);
                    254: 
                    255:                xa = _mm_add_epi32(xa, xf); x5 = rotlxor32(x5, xa, 7);
                    256:                xb = _mm_add_epi32(xb, xc); x6 = rotlxor32(x6, xb, 7);
                    257:                x8 = _mm_add_epi32(x8, xd); x7 = rotlxor32(x7, x8, 7);
                    258:                x9 = _mm_add_epi32(x9, xe); x4 = rotlxor32(x4, x9, 7);
                    259:        }
                    260: 
                    261:        x0 = _mm_add_epi32(x0, _mm_set1_epi32(m[ 0]));
                    262:        x1 = _mm_add_epi32(x1, _mm_set1_epi32(m[ 1]));
                    263:        x2 = _mm_add_epi32(x2, _mm_set1_epi32(m[ 2]));
                    264:        x3 = _mm_add_epi32(x3, _mm_set1_epi32(m[ 3]));
                    265:        x4 = _mm_add_epi32(x4, _mm_set1_epi32(m[ 4]));
                    266:        x5 = _mm_add_epi32(x5, _mm_set1_epi32(m[ 5]));
                    267:        x6 = _mm_add_epi32(x6, _mm_set1_epi32(m[ 6]));
                    268:        x7 = _mm_add_epi32(x7, _mm_set1_epi32(m[ 7]));
                    269:        x8 = _mm_add_epi32(x8, _mm_set1_epi32(m[ 8]));
                    270:        x9 = _mm_add_epi32(x9, _mm_set1_epi32(m[ 9]));
                    271:        xa = _mm_add_epi32(xa, _mm_set1_epi32(m[10]));
                    272:        xb = _mm_add_epi32(xb, _mm_set1_epi32(m[11]));
                    273:        xc = _mm_add_epi32(xc, _mm_set1_epi32(m[12]));
                    274:        xd = _mm_add_epi32(xd, _mm_set1_epi32(m[13]));
                    275:        xe = _mm_add_epi32(xe, _mm_set1_epi32(m[14]));
                    276:        xf = _mm_add_epi32(xf, _mm_set1_epi32(m[15]));
                    277: 
                    278:        xc = _mm_add_epi32(xc, ctrinc);
                    279: 
                    280:        /* transpose state matrix by interleaving 32-, then 64-bit words */
                    281:        t = x0; x0 = _mm_unpacklo_epi32(t, x1);
                    282:                        x1 = _mm_unpackhi_epi32(t, x1);
                    283:        t = x2; x2 = _mm_unpacklo_epi32(t, x3);
                    284:                        x3 = _mm_unpackhi_epi32(t, x3);
                    285:        t = x4; x4 = _mm_unpacklo_epi32(t, x5);
                    286:                        x5 = _mm_unpackhi_epi32(t, x5);
                    287:        t = x6; x6 = _mm_unpacklo_epi32(t, x7);
                    288:                        x7 = _mm_unpackhi_epi32(t, x7);
                    289:        t = x8; x8 = _mm_unpacklo_epi32(t, x9);
                    290:                        x9 = _mm_unpackhi_epi32(t, x9);
                    291:        t = xa; xa = _mm_unpacklo_epi32(t, xb);
                    292:                        xb = _mm_unpackhi_epi32(t, xb);
                    293:        t = xc; xc = _mm_unpacklo_epi32(t, xd);
                    294:                        xd = _mm_unpackhi_epi32(t, xd);
                    295:        t = xe; xe = _mm_unpacklo_epi32(t, xf);
                    296:                        xf = _mm_unpackhi_epi32(t, xf);
                    297: 
                    298:        t = x0; x0 = _mm_unpacklo_epi64(t, x2);
                    299:                        x2 = _mm_unpackhi_epi64(t, x2);
                    300:        t = x1; x1 = _mm_unpacklo_epi64(t, x3);
                    301:                        x3 = _mm_unpackhi_epi64(t, x3);
                    302:        t = x4; x4 = _mm_unpacklo_epi64(t, x6);
                    303:                        x6 = _mm_unpackhi_epi64(t, x6);
                    304:        t = x5; x5 = _mm_unpacklo_epi64(t, x7);
                    305:                        x7 = _mm_unpackhi_epi64(t, x7);
                    306:        t = x8; x8 = _mm_unpacklo_epi64(t, xa);
                    307:                        xa = _mm_unpackhi_epi64(t, xa);
                    308:        t = x9; x9 = _mm_unpacklo_epi64(t, xb);
                    309:                        xb = _mm_unpackhi_epi64(t, xb);
                    310:        t = xc; xc = _mm_unpacklo_epi64(t, xe);
                    311:                        xe = _mm_unpackhi_epi64(t, xe);
                    312:        t = xd; xd = _mm_unpacklo_epi64(t, xf);
                    313:                        xf = _mm_unpackhi_epi64(t, xf);
                    314: 
                    315:        x0 = _mm_xor_si128(_mm_loadu_si128(out +  0), x0);
                    316:        x1 = _mm_xor_si128(_mm_loadu_si128(out +  8), x1);
                    317:        x2 = _mm_xor_si128(_mm_loadu_si128(out +  4), x2);
                    318:        x3 = _mm_xor_si128(_mm_loadu_si128(out + 12), x3);
                    319:        x4 = _mm_xor_si128(_mm_loadu_si128(out +  1), x4);
                    320:        x5 = _mm_xor_si128(_mm_loadu_si128(out +  9), x5);
                    321:        x6 = _mm_xor_si128(_mm_loadu_si128(out +  5), x6);
                    322:        x7 = _mm_xor_si128(_mm_loadu_si128(out + 13), x7);
                    323:        x8 = _mm_xor_si128(_mm_loadu_si128(out +  2), x8);
                    324:        x9 = _mm_xor_si128(_mm_loadu_si128(out + 10), x9);
                    325:        xa = _mm_xor_si128(_mm_loadu_si128(out +  6), xa);
                    326:        xb = _mm_xor_si128(_mm_loadu_si128(out + 14), xb);
                    327:        xc = _mm_xor_si128(_mm_loadu_si128(out +  3), xc);
                    328:        xd = _mm_xor_si128(_mm_loadu_si128(out + 11), xd);
                    329:        xe = _mm_xor_si128(_mm_loadu_si128(out +  7), xe);
                    330:        xf = _mm_xor_si128(_mm_loadu_si128(out + 15), xf);
                    331: 
                    332:        _mm_storeu_si128(out +  0, x0);
                    333:        _mm_storeu_si128(out +  8, x1);
                    334:        _mm_storeu_si128(out +  4, x2);
                    335:        _mm_storeu_si128(out + 12, x3);
                    336:        _mm_storeu_si128(out +  1, x4);
                    337:        _mm_storeu_si128(out +  9, x5);
                    338:        _mm_storeu_si128(out +  5, x6);
                    339:        _mm_storeu_si128(out + 13, x7);
                    340:        _mm_storeu_si128(out +  2, x8);
                    341:        _mm_storeu_si128(out + 10, x9);
                    342:        _mm_storeu_si128(out +  6, xa);
                    343:        _mm_storeu_si128(out + 14, xb);
                    344:        _mm_storeu_si128(out +  3, xc);
                    345:        _mm_storeu_si128(out + 11, xd);
                    346:        _mm_storeu_si128(out +  7, xe);
                    347:        _mm_storeu_si128(out + 15, xf);
                    348: 
                    349:        this->m[3] = _mm_add_epi32(this->m[3], _mm_set_epi32(0, 0, 0, 4));
                    350: }
                    351: 
                    352: METHOD(chapoly_drv_t, set_key, bool,
                    353:        private_chapoly_drv_ssse3_t *this, u_char *constant, u_char *key,
                    354:        u_char *salt)
                    355: {
                    356:        this->m[0] = _mm_loadu_si128((__m128i*)constant);
                    357:        this->m[1] = _mm_loadu_si128((__m128i*)key + 0);
                    358:        this->m[2] = _mm_loadu_si128((__m128i*)key + 1);
                    359:        this->m[3] = _mm_set_epi32(0, 0, ru32(salt), 0);
                    360: 
                    361:        return TRUE;
                    362: }
                    363: 
                    364: /**
                    365:  * r[127:64] = h[95:64] * a, r[63:0] = h[31:0] * b
                    366:  */
                    367: static inline __m128i mul2(__m128i h, uint32_t a, uint32_t b)
                    368: {
                    369:        return _mm_mul_epu32(h, _mm_set_epi32(0, a, 0, b));
                    370: }
                    371: 
                    372: /**
                    373:  * c = a[127:64] + a[63:0] + b[127:64] + b[63:0]
                    374:  * z = x[127:64] + x[63:0] + y[127:64] + y[63:0]
                    375:  */
                    376: static inline void sum2(__m128i a, __m128i b, __m128i x, __m128i y,
                    377:                                                uint64_t *c, uint64_t *z)
                    378: {
                    379:        __m128i r, s;
                    380: 
                    381:        a = _mm_add_epi64(a, b);
                    382:        x = _mm_add_epi64(x, y);
                    383:        r = _mm_unpacklo_epi64(x, a);
                    384:        s = _mm_unpackhi_epi64(x, a);
                    385:        r = _mm_add_epi64(r, s);
                    386: 
                    387:        _mm_storel_epi64((__m128i*)z, r);
                    388:        _mm_storel_epi64((__m128i*)c, _mm_srli_si128(r, 8));
                    389: }
                    390: 
                    391: /**
                    392:  * r = a[127:64] + b[127:64] + c[127:64] + d[127:64] + e[127:64]
                    393:  *   + a[63:0]   + b[63:0]   + c[63:0]   + d[63:0]   + e[63:0]
                    394:  */
                    395: static inline uint64_t sum5(__m128i a, __m128i b, __m128i c,
                    396:                                                         __m128i d, __m128i e)
                    397: {
                    398:        uint64_t r;
                    399: 
                    400:        a = _mm_add_epi64(a, b);
                    401:        c = _mm_add_epi64(c, d);
                    402:        a = _mm_add_epi64(a, e);
                    403:        a = _mm_add_epi64(a, c);
                    404: 
                    405:        a = _mm_add_epi64(a, _mm_srli_si128(a, 8));
                    406:        _mm_storel_epi64((__m128i*)&r, a);
                    407: 
                    408:        return r;
                    409: }
                    410: 
                    411: /**
                    412:  * Make second Poly1305 key u = r^2
                    413:  */
                    414: static void make_u(private_chapoly_drv_ssse3_t *this)
                    415: {
                    416:        __m128i r01, r23, r44, x0, x1, y0, y1, z0;
                    417:        uint32_t r0, r1, r2, r3, r4;
                    418:        uint32_t u0, u1, u2, u3, u4;
                    419:        uint32_t s1, s2, s3, s4;
                    420:        uint64_t d0, d1, d2, d3, d4;
                    421: 
                    422:        r0 = this->r[0];
                    423:        r1 = this->r[1];
                    424:        r2 = this->r[2];
                    425:        r3 = this->r[3];
                    426:        r4 = this->r[4];
                    427: 
                    428:        s1 = r1 * 5;
                    429:        s2 = r2 * 5;
                    430:        s3 = r3 * 5;
                    431:        s4 = r4 * 5;
                    432: 
                    433:        r01 = _mm_set_epi32(0, r0, 0, r1);
                    434:        r23 = _mm_set_epi32(0, r2, 0, r3);
                    435:        r44 = _mm_set_epi32(0, r4, 0, r4);
                    436: 
                    437:        /* u = r^2 */
                    438:        x0 = mul2(r01, r0, s4);
                    439:        x1 = mul2(r01, r1, r0);
                    440:        y0 = mul2(r23, s3, s2);
                    441:        y1 = mul2(r23, s4, s3);
                    442:        z0 = mul2(r44, s1, s2);
                    443:        y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
                    444:        y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
                    445:        sum2(x0, y0, x1, y1, &d0, &d1);
                    446: 
                    447:        x0 = mul2(r01, r2, r1);
                    448:        x1 = mul2(r01, r3, r2);
                    449:        y0 = mul2(r23, r0, s4);
                    450:        y1 = mul2(r23, r1, r0);
                    451:        z0 = mul2(r44, s3, s4);
                    452:        y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
                    453:        y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
                    454:        sum2(x0, y0, x1, y1, &d2, &d3);
                    455: 
                    456:        x0 = mul2(r01, r4, r3);
                    457:        y0 = mul2(r23, r2, r1);
                    458:        z0 = mul2(r44, r0, 0);
                    459:        y0 = _mm_add_epi64(y0, z0);
                    460:        x0 = _mm_add_epi64(x0, y0);
                    461:        x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
                    462:        _mm_storel_epi64((__m128i*)&d4, x0);
                    463: 
                    464:        /* (partial) r %= p */
                    465:        d1 += sr(d0, 26);     u0 = and(d0, 0x3ffffff);
                    466:        d2 += sr(d1, 26);     u1 = and(d1, 0x3ffffff);
                    467:        d3 += sr(d2, 26);     u2 = and(d2, 0x3ffffff);
                    468:        d4 += sr(d3, 26);     u3 = and(d3, 0x3ffffff);
                    469:        u0 += sr(d4, 26) * 5; u4 = and(d4, 0x3ffffff);
                    470:        u1 += u0 >> 26;       u0 &= 0x3ffffff;
                    471: 
                    472:        this->u[0] = u0;
                    473:        this->u[1] = u1;
                    474:        this->u[2] = u2;
                    475:        this->u[3] = u3;
                    476:        this->u[4] = u4;
                    477: }
                    478: 
                    479: METHOD(chapoly_drv_t, init, bool,
                    480:        private_chapoly_drv_ssse3_t *this, u_char *iv)
                    481: {
                    482:        u_char key[CHACHA_BLOCK_SIZE];
                    483: 
                    484:        this->m[3] = _mm_or_si128(
                    485:                                        _mm_set_epi32(ru32(iv + 4), ru32(iv + 0), 0, 0),
                    486:                                        _mm_and_si128(this->m[3], _mm_set_epi32(0, 0, ~0, 0)));
                    487: 
                    488:        memset(key, 0, CHACHA_BLOCK_SIZE);
                    489:        chacha_block_xor(this, key);
                    490: 
                    491:        /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
                    492:        this->r[0] = (ru32(key +  0) >> 0) & 0x3ffffff;
                    493:        this->r[1] = (ru32(key +  3) >> 2) & 0x3ffff03;
                    494:        this->r[2] = (ru32(key +  6) >> 4) & 0x3ffc0ff;
                    495:        this->r[3] = (ru32(key +  9) >> 6) & 0x3f03fff;
                    496:        this->r[4] = (ru32(key + 12) >> 8) & 0x00fffff;
                    497: 
                    498:        make_u(this);
                    499: 
                    500:        /* h = 0 */
                    501:        memwipe(this->h, sizeof(this->h));
                    502: 
                    503:        this->s[0] = ru32(key + 16);
                    504:        this->s[1] = ru32(key + 20);
                    505:        this->s[2] = ru32(key + 24);
                    506:        this->s[3] = ru32(key + 28);
                    507: 
                    508:        return TRUE;
                    509: }
                    510: 
                    511: /**
                    512:  * Update Poly1305 for a multiple of two blocks
                    513:  */
                    514: static void poly2(private_chapoly_drv_ssse3_t *this, u_char *data, u_int dblks)
                    515: {
                    516:        uint32_t r0, r1, r2, r3, r4, u0, u1, u2, u3, u4;
                    517:        uint32_t s1, s2, s3, s4, v1, v2, v3, v4;
                    518:        __m128i hc0, hc1, hc2, hc3, hc4;
                    519:        uint32_t h0, h1, h2, h3, h4;
                    520:        uint32_t c0, c1, c2, c3, c4;
                    521:        uint64_t d0, d1, d2, d3, d4;
                    522:        u_int i;
                    523: 
                    524:        r0 = this->r[0];
                    525:        r1 = this->r[1];
                    526:        r2 = this->r[2];
                    527:        r3 = this->r[3];
                    528:        r4 = this->r[4];
                    529: 
                    530:        s1 = r1 * 5;
                    531:        s2 = r2 * 5;
                    532:        s3 = r3 * 5;
                    533:        s4 = r4 * 5;
                    534: 
                    535:        u0 = this->u[0];
                    536:        u1 = this->u[1];
                    537:        u2 = this->u[2];
                    538:        u3 = this->u[3];
                    539:        u4 = this->u[4];
                    540: 
                    541:        v1 = u1 * 5;
                    542:        v2 = u2 * 5;
                    543:        v3 = u3 * 5;
                    544:        v4 = u4 * 5;
                    545: 
                    546:        h0 = this->h[0];
                    547:        h1 = this->h[1];
                    548:        h2 = this->h[2];
                    549:        h3 = this->h[3];
                    550:        h4 = this->h[4];
                    551: 
                    552:        /* h = (h + c1) * r^2 + c2 * r */
                    553:        for (i = 0; i < dblks; i++)
                    554:        {
                    555:                /* h += m[i] */
                    556:                h0 += (ru32(data +  0) >> 0) & 0x3ffffff;
                    557:                h1 += (ru32(data +  3) >> 2) & 0x3ffffff;
                    558:                h2 += (ru32(data +  6) >> 4) & 0x3ffffff;
                    559:                h3 += (ru32(data +  9) >> 6) & 0x3ffffff;
                    560:                h4 += (ru32(data + 12) >> 8) | (1 << 24);
                    561:                data += POLY_BLOCK_SIZE;
                    562: 
                    563:                /* c = m[i + 1] */
                    564:                c0 = (ru32(data +  0) >> 0) & 0x3ffffff;
                    565:                c1 = (ru32(data +  3) >> 2) & 0x3ffffff;
                    566:                c2 = (ru32(data +  6) >> 4) & 0x3ffffff;
                    567:                c3 = (ru32(data +  9) >> 6) & 0x3ffffff;
                    568:                c4 = (ru32(data + 12) >> 8) | (1 << 24);
                    569:                data += POLY_BLOCK_SIZE;
                    570: 
                    571:                hc0 = _mm_set_epi32(0, h0, 0, c0);
                    572:                hc1 = _mm_set_epi32(0, h1, 0, c1);
                    573:                hc2 = _mm_set_epi32(0, h2, 0, c2);
                    574:                hc3 = _mm_set_epi32(0, h3, 0, c3);
                    575:                hc4 = _mm_set_epi32(0, h4, 0, c4);
                    576: 
                    577:                /* h = h * r^2 + c * r */
                    578:                d0 = sum5(mul2(hc0, u0, r0),
                    579:                                  mul2(hc1, v4, s4),
                    580:                                  mul2(hc2, v3, s3),
                    581:                                  mul2(hc3, v2, s2),
                    582:                                  mul2(hc4, v1, s1));
                    583:                d1 = sum5(mul2(hc0, u1, r1),
                    584:                                  mul2(hc1, u0, r0),
                    585:                                  mul2(hc2, v4, s4),
                    586:                                  mul2(hc3, v3, s3),
                    587:                                  mul2(hc4, v2, s2));
                    588:                d2 = sum5(mul2(hc0, u2, r2),
                    589:                                  mul2(hc1, u1, r1),
                    590:                                  mul2(hc2, u0, r0),
                    591:                                  mul2(hc3, v4, s4),
                    592:                                  mul2(hc4, v3, s3));
                    593:                d3 = sum5(mul2(hc0, u3, r3),
                    594:                                  mul2(hc1, u2, r2),
                    595:                                  mul2(hc2, u1, r1),
                    596:                                  mul2(hc3, u0, r0),
                    597:                                  mul2(hc4, v4, s4));
                    598:                d4 = sum5(mul2(hc0, u4, r4),
                    599:                                  mul2(hc1, u3, r3),
                    600:                                  mul2(hc2, u2, r2),
                    601:                                  mul2(hc3, u1, r1),
                    602:                                  mul2(hc4, u0, r0));
                    603: 
                    604:                /* (partial) h %= p */
                    605:                d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
                    606:                d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
                    607:                d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
                    608:                d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
                    609:                h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
                    610:                h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
                    611:        }
                    612: 
                    613:        this->h[0] = h0;
                    614:        this->h[1] = h1;
                    615:        this->h[2] = h2;
                    616:        this->h[3] = h3;
                    617:        this->h[4] = h4;
                    618: }
                    619: 
                    620: /**
                    621:  * Update Poly1305 for a single block
                    622:  */
                    623: static void poly1(private_chapoly_drv_ssse3_t *this, u_char *data)
                    624: {
                    625:        uint32_t r0, r1, r2, r3, r4;
                    626:        uint32_t s1, s2, s3, s4;
                    627:        uint32_t h0, h1, h2, h3, h4;
                    628:        uint64_t d0, d1, d2, d3, d4;
                    629:        __m128i h01, h23, h44;
                    630:        __m128i x0, x1, y0, y1, z0;
                    631:        uint32_t t0, t1;
                    632: 
                    633:        r0 = this->r[0];
                    634:        r1 = this->r[1];
                    635:        r2 = this->r[2];
                    636:        r3 = this->r[3];
                    637:        r4 = this->r[4];
                    638: 
                    639:        s1 = r1 * 5;
                    640:        s2 = r2 * 5;
                    641:        s3 = r3 * 5;
                    642:        s4 = r4 * 5;
                    643: 
                    644:        h0 = this->h[0];
                    645:        h1 = this->h[1];
                    646:        h2 = this->h[2];
                    647:        h3 = this->h[3];
                    648:        h4 = this->h[4];
                    649: 
                    650:        h01 = _mm_set_epi32(0, h0, 0, h1);
                    651:        h23 = _mm_set_epi32(0, h2, 0, h3);
                    652:        h44 = _mm_set_epi32(0, h4, 0, h4);
                    653: 
                    654:        /* h += m[i] */
                    655:        t0  = (ru32(data +  0) >> 0) & 0x3ffffff;
                    656:        t1  = (ru32(data +  3) >> 2) & 0x3ffffff;
                    657:        h01 = _mm_add_epi32(h01, _mm_set_epi32(0, t0, 0, t1));
                    658:        t0  = (ru32(data +  6) >> 4) & 0x3ffffff;
                    659:        t1  = (ru32(data +  9) >> 6) & 0x3ffffff;
                    660:        h23 = _mm_add_epi32(h23, _mm_set_epi32(0, t0, 0, t1));
                    661:        t0  = (ru32(data + 12) >> 8) | (1 << 24);
                    662:        h44 = _mm_add_epi32(h44, _mm_set_epi32(0, t0, 0, t0));
                    663: 
                    664:        /* h *= r */
                    665:        x0 = mul2(h01, r0, s4);
                    666:        x1 = mul2(h01, r1, r0);
                    667:        y0 = mul2(h23, s3, s2);
                    668:        y1 = mul2(h23, s4, s3);
                    669:        z0 = mul2(h44, s1, s2);
                    670:        y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
                    671:        y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
                    672:        sum2(x0, y0, x1, y1, &d0, &d1);
                    673: 
                    674:        x0 = mul2(h01, r2, r1);
                    675:        x1 = mul2(h01, r3, r2);
                    676:        y0 = mul2(h23, r0, s4);
                    677:        y1 = mul2(h23, r1, r0);
                    678:        z0 = mul2(h44, s3, s4);
                    679:        y0 = _mm_add_epi64(y0, _mm_srli_si128(z0, 8));
                    680:        y1 = _mm_add_epi64(y1, _mm_slli_si128(z0, 8));
                    681:        sum2(x0, y0, x1, y1, &d2, &d3);
                    682: 
                    683:        x0 = mul2(h01, r4, r3);
                    684:        y0 = mul2(h23, r2, r1);
                    685:        z0 = mul2(h44, r0, 0);
                    686:        y0 = _mm_add_epi64(y0, z0);
                    687:        x0 = _mm_add_epi64(x0, y0);
                    688:        x0 = _mm_add_epi64(x0, _mm_srli_si128(x0, 8));
                    689:        _mm_storel_epi64((__m128i*)&d4, x0);
                    690: 
                    691:        /* (partial) h %= p */
                    692:        d1 += sr(d0, 26);     h0 = and(d0, 0x3ffffff);
                    693:        d2 += sr(d1, 26);     h1 = and(d1, 0x3ffffff);
                    694:        d3 += sr(d2, 26);     h2 = and(d2, 0x3ffffff);
                    695:        d4 += sr(d3, 26);     h3 = and(d3, 0x3ffffff);
                    696:        h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff);
                    697:        h1 += h0 >> 26;       h0 = h0 & 0x3ffffff;
                    698: 
                    699:        this->h[0] = h0;
                    700:        this->h[1] = h1;
                    701:        this->h[2] = h2;
                    702:        this->h[3] = h3;
                    703:        this->h[4] = h4;
                    704: }
                    705: 
                    706: METHOD(chapoly_drv_t, poly, bool,
                    707:        private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
                    708: {
                    709:        poly2(this, data, blocks / 2);
                    710:        if (blocks-- % 2)
                    711:        {
                    712:                poly1(this, data + POLY_BLOCK_SIZE * blocks);
                    713:        }
                    714:        return TRUE;
                    715: }
                    716: 
                    717: METHOD(chapoly_drv_t, chacha, bool,
                    718:        private_chapoly_drv_ssse3_t *this, u_char *stream)
                    719: {
                    720:        memset(stream, 0, CHACHA_BLOCK_SIZE);
                    721:        chacha_block_xor(this, stream);
                    722: 
                    723:        return TRUE;
                    724: }
                    725: 
                    726: METHOD(chapoly_drv_t, encrypt, bool,
                    727:        private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
                    728: {
                    729:        while (blocks >= 4)
                    730:        {
                    731:                chacha_4block_xor(this, data);
                    732:                poly2(this, data, 8);
                    733:                data += CHACHA_BLOCK_SIZE * 4;
                    734:                blocks -= 4;
                    735:        }
                    736:        while (blocks--)
                    737:        {
                    738:                chacha_block_xor(this, data);
                    739:                poly2(this, data, 2);
                    740:                data += CHACHA_BLOCK_SIZE;
                    741:        }
                    742:        return TRUE;
                    743: }
                    744: 
                    745: METHOD(chapoly_drv_t, decrypt, bool,
                    746:        private_chapoly_drv_ssse3_t *this, u_char *data, u_int blocks)
                    747: {
                    748:        while (blocks >= 4)
                    749:        {
                    750:                poly2(this, data, 8);
                    751:                chacha_4block_xor(this, data);
                    752:                data += CHACHA_BLOCK_SIZE * 4;
                    753:                blocks -= 4;
                    754:        }
                    755:        while (blocks--)
                    756:        {
                    757:                poly2(this, data, 2);
                    758:                chacha_block_xor(this, data);
                    759:                data += CHACHA_BLOCK_SIZE;
                    760:        }
                    761:        return TRUE;
                    762: }
                    763: 
                    764: METHOD(chapoly_drv_t, finish, bool,
                    765:        private_chapoly_drv_ssse3_t *this, u_char *mac)
                    766: {
                    767:        uint32_t h0, h1, h2, h3, h4;
                    768:        uint32_t g0, g1, g2, g3, g4;
                    769:        uint32_t mask;
                    770:        uint64_t f = 0;
                    771: 
                    772:        /* fully carry h */
                    773:        h0 = this->h[0];
                    774:        h1 = this->h[1];
                    775:        h2 = this->h[2];
                    776:        h3 = this->h[3];
                    777:        h4 = this->h[4];
                    778: 
                    779:        h2 += (h1 >> 26);     h1 = h1 & 0x3ffffff;
                    780:        h3 += (h2 >> 26);     h2 = h2 & 0x3ffffff;
                    781:        h4 += (h3 >> 26);     h3 = h3 & 0x3ffffff;
                    782:        h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff;
                    783:        h1 += (h0 >> 26);     h0 = h0 & 0x3ffffff;
                    784: 
                    785:        /* compute h + -p */
                    786:        g0 = h0 + 5;
                    787:        g1 = h1 + (g0 >> 26);             g0 &= 0x3ffffff;
                    788:        g2 = h2 + (g1 >> 26);             g1 &= 0x3ffffff;
                    789:        g3 = h3 + (g2 >> 26);             g2 &= 0x3ffffff;
                    790:        g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff;
                    791: 
                    792:        /* select h if h < p, or h + -p if h >= p */
                    793:        mask = (g4 >> ((sizeof(uint32_t) * 8) - 1)) - 1;
                    794:        g0 &= mask;
                    795:        g1 &= mask;
                    796:        g2 &= mask;
                    797:        g3 &= mask;
                    798:        g4 &= mask;
                    799:        mask = ~mask;
                    800:        h0 = (h0 & mask) | g0;
                    801:        h1 = (h1 & mask) | g1;
                    802:        h2 = (h2 & mask) | g2;
                    803:        h3 = (h3 & mask) | g3;
                    804:        h4 = (h4 & mask) | g4;
                    805: 
                    806:        /* h = h % (2^128) */
                    807:        h0 = (h0 >>  0) | (h1 << 26);
                    808:        h1 = (h1 >>  6) | (h2 << 20);
                    809:        h2 = (h2 >> 12) | (h3 << 14);
                    810:        h3 = (h3 >> 18) | (h4 <<  8);
                    811: 
                    812:        /* mac = (h + s) % (2^128) */
                    813:        f = (f >> 32) + h0 + this->s[0]; wu32(mac +  0, f);
                    814:        f = (f >> 32) + h1 + this->s[1]; wu32(mac +  4, f);
                    815:        f = (f >> 32) + h2 + this->s[2]; wu32(mac +  8, f);
                    816:        f = (f >> 32) + h3 + this->s[3]; wu32(mac + 12, f);
                    817: 
                    818:        return TRUE;
                    819: }
                    820: 
                    821: METHOD(chapoly_drv_t, destroy, void,
                    822:        private_chapoly_drv_ssse3_t *this)
                    823: {
                    824:        memwipe(this->m, sizeof(this->m));
                    825:        memwipe(this->h, sizeof(this->h));
                    826:        memwipe(this->r, sizeof(this->r));
                    827:        memwipe(this->u, sizeof(this->u));
                    828:        memwipe(this->s, sizeof(this->s));
                    829:        free_align(this);
                    830: }
                    831: 
                    832: /**
                    833:  * See header
                    834:  */
                    835: chapoly_drv_t *chapoly_drv_ssse3_create()
                    836: {
                    837:        private_chapoly_drv_ssse3_t *this;
                    838: 
                    839:        if (!cpu_feature_available(CPU_FEATURE_SSSE3))
                    840:        {
                    841:                return FALSE;
                    842:        }
                    843: 
                    844:        INIT_ALIGN(this, sizeof(__m128i),
                    845:                .public = {
                    846:                        .set_key = _set_key,
                    847:                        .init = _init,
                    848:                        .poly = _poly,
                    849:                        .chacha = _chacha,
                    850:                        .encrypt = _encrypt,
                    851:                        .decrypt = _decrypt,
                    852:                        .finish = _finish,
                    853:                        .destroy = _destroy,
                    854:                },
                    855:        );
                    856: 
                    857:        return &this->public;
                    858: }
                    859: 
                    860: #else /* !__SSSE3__ */
                    861: 
                    862: chapoly_drv_t *chapoly_drv_ssse3_create()
                    863: {
                    864:        return NULL;
                    865: }
                    866: 
                    867: #endif /* !__SSSE3__ */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>