xref: /isa-l_crypto/sha256_mb/sha256_ctx_avx.c (revision 0a437795c8360736f38dfa5934aa03a1861d784c)
16df3ef80SGreg Tucker /**********************************************************************
26df3ef80SGreg Tucker   Copyright(c) 2011-2016 Intel Corporation All rights reserved.
36df3ef80SGreg Tucker 
46df3ef80SGreg Tucker   Redistribution and use in source and binary forms, with or without
56df3ef80SGreg Tucker   modification, are permitted provided that the following conditions
66df3ef80SGreg Tucker   are met:
76df3ef80SGreg Tucker     * Redistributions of source code must retain the above copyright
86df3ef80SGreg Tucker       notice, this list of conditions and the following disclaimer.
96df3ef80SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
106df3ef80SGreg Tucker       notice, this list of conditions and the following disclaimer in
116df3ef80SGreg Tucker       the documentation and/or other materials provided with the
126df3ef80SGreg Tucker       distribution.
136df3ef80SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
146df3ef80SGreg Tucker       contributors may be used to endorse or promote products derived
156df3ef80SGreg Tucker       from this software without specific prior written permission.
166df3ef80SGreg Tucker 
176df3ef80SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186df3ef80SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196df3ef80SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206df3ef80SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216df3ef80SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226df3ef80SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236df3ef80SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246df3ef80SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256df3ef80SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266df3ef80SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276df3ef80SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286df3ef80SGreg Tucker **********************************************************************/
296df3ef80SGreg Tucker 
30a6dc8696SGreg Tucker #if defined(__clang__)
31a6dc8696SGreg Tucker #pragma clang attribute push(__attribute__((target("avx"))), apply_to = function)
32a6dc8696SGreg Tucker #elif defined(__ICC)
33a6dc8696SGreg Tucker #pragma intel optimization_parameter target_arch = AVX
34a6dc8696SGreg Tucker #elif defined(__ICL)
35a6dc8696SGreg Tucker #pragma[intel] optimization_parameter target_arch = AVX
36a6dc8696SGreg Tucker #elif (__GNUC__ >= 5)
37a6dc8696SGreg Tucker #pragma GCC target("avx")
38a6dc8696SGreg Tucker #endif
39a6dc8696SGreg Tucker 
403c423071SPablo de Lara #include "sha256_mb_internal.h"
416df3ef80SGreg Tucker #include "memcpy_inline.h"
4292aa5aa4SGreg Tucker #include "endian_helper.h"
436df3ef80SGreg Tucker 
446df3ef80SGreg Tucker #ifdef _MSC_VER
456df3ef80SGreg Tucker #include <intrin.h>
466df3ef80SGreg Tucker #define inline __inline
476df3ef80SGreg Tucker #endif
486df3ef80SGreg Tucker 
499ba6f238SMarcel Cornu static inline void
50*0a437795SPablo de Lara hash_init_digest(ISAL_SHA256_WORD_T *digest);
519ba6f238SMarcel Cornu static inline uint32_t
52*0a437795SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2], uint64_t total_len);
53*0a437795SPablo de Lara static ISAL_SHA256_HASH_CTX *
54*0a437795SPablo de Lara sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx);
556df3ef80SGreg Tucker 
569ba6f238SMarcel Cornu void
_sha256_ctx_mgr_init_avx(ISAL_SHA256_HASH_CTX_MGR * mgr)57*0a437795SPablo de Lara _sha256_ctx_mgr_init_avx(ISAL_SHA256_HASH_CTX_MGR *mgr)
586df3ef80SGreg Tucker {
593c423071SPablo de Lara         _sha256_mb_mgr_init_avx(&mgr->mgr);
606df3ef80SGreg Tucker }
616df3ef80SGreg Tucker 
62*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *
_sha256_ctx_mgr_submit_avx(ISAL_SHA256_HASH_CTX_MGR * mgr,ISAL_SHA256_HASH_CTX * ctx,const void * buffer,uint32_t len,ISAL_HASH_CTX_FLAG flags)63*0a437795SPablo de Lara _sha256_ctx_mgr_submit_avx(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx,
64*0a437795SPablo de Lara                            const void *buffer, uint32_t len, ISAL_HASH_CTX_FLAG flags)
656df3ef80SGreg Tucker {
668cb7fe78SPablo de Lara         if (flags & (~ISAL_HASH_ENTIRE)) {
676df3ef80SGreg Tucker                 // User should not pass anything other than FIRST, UPDATE, or LAST
688cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_INVALID_FLAGS;
696df3ef80SGreg Tucker                 return ctx;
706df3ef80SGreg Tucker         }
716df3ef80SGreg Tucker 
728cb7fe78SPablo de Lara         if (ctx->status & ISAL_HASH_CTX_STS_PROCESSING) {
736df3ef80SGreg Tucker                 // Cannot submit to a currently processing job.
748cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_PROCESSING;
756df3ef80SGreg Tucker                 return ctx;
766df3ef80SGreg Tucker         }
776df3ef80SGreg Tucker 
788cb7fe78SPablo de Lara         if ((ctx->status & ISAL_HASH_CTX_STS_COMPLETE) && !(flags & ISAL_HASH_FIRST)) {
796df3ef80SGreg Tucker                 // Cannot update a finished job.
808cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_COMPLETED;
816df3ef80SGreg Tucker                 return ctx;
826df3ef80SGreg Tucker         }
836df3ef80SGreg Tucker 
848cb7fe78SPablo de Lara         if (flags & ISAL_HASH_FIRST) {
856df3ef80SGreg Tucker                 // Init digest
866df3ef80SGreg Tucker                 hash_init_digest(ctx->job.result_digest);
876df3ef80SGreg Tucker 
886df3ef80SGreg Tucker                 // Reset byte counter
896df3ef80SGreg Tucker                 ctx->total_length = 0;
906df3ef80SGreg Tucker 
916df3ef80SGreg Tucker                 // Clear extra blocks
926df3ef80SGreg Tucker                 ctx->partial_block_buffer_length = 0;
936df3ef80SGreg Tucker         }
946df3ef80SGreg Tucker         // If we made it here, there were no errors during this call to submit
958cb7fe78SPablo de Lara         ctx->error = ISAL_HASH_CTX_ERROR_NONE;
966df3ef80SGreg Tucker 
976df3ef80SGreg Tucker         // Store buffer ptr info from user
986df3ef80SGreg Tucker         ctx->incoming_buffer = buffer;
996df3ef80SGreg Tucker         ctx->incoming_buffer_length = len;
1006df3ef80SGreg Tucker 
1016df3ef80SGreg Tucker         // Store the user's request flags and mark this ctx as currently being processed.
1028cb7fe78SPablo de Lara         ctx->status = (flags & ISAL_HASH_LAST) ? (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
1038cb7fe78SPablo de Lara                                                                       ISAL_HASH_CTX_STS_LAST)
1048cb7fe78SPablo de Lara                                                : ISAL_HASH_CTX_STS_PROCESSING;
1056df3ef80SGreg Tucker 
1066df3ef80SGreg Tucker         // Advance byte counter
1076df3ef80SGreg Tucker         ctx->total_length += len;
1086df3ef80SGreg Tucker 
1099ba6f238SMarcel Cornu         // If there is anything currently buffered in the extra blocks, append to it until it
1109ba6f238SMarcel Cornu         // contains a whole block. Or if the user's buffer contains less than a whole block, append
1119ba6f238SMarcel Cornu         // as much as possible to the extra block.
112*0a437795SPablo de Lara         if ((ctx->partial_block_buffer_length) | (len < ISAL_SHA256_BLOCK_SIZE)) {
1136df3ef80SGreg Tucker                 // Compute how many bytes to copy from user buffer into extra block
114*0a437795SPablo de Lara                 uint32_t copy_len = ISAL_SHA256_BLOCK_SIZE - ctx->partial_block_buffer_length;
1156df3ef80SGreg Tucker                 if (len < copy_len)
1166df3ef80SGreg Tucker                         copy_len = len;
1176df3ef80SGreg Tucker 
1186df3ef80SGreg Tucker                 if (copy_len) {
1196df3ef80SGreg Tucker                         // Copy and update relevant pointers and counters
1209ba6f238SMarcel Cornu                         memcpy_varlen(&ctx->partial_block_buffer[ctx->partial_block_buffer_length],
1219ba6f238SMarcel Cornu                                       buffer, copy_len);
1226df3ef80SGreg Tucker 
1236df3ef80SGreg Tucker                         ctx->partial_block_buffer_length += copy_len;
1246df3ef80SGreg Tucker                         ctx->incoming_buffer = (const void *) ((const char *) buffer + copy_len);
1256df3ef80SGreg Tucker                         ctx->incoming_buffer_length = len - copy_len;
1266df3ef80SGreg Tucker                 }
1276df3ef80SGreg Tucker                 // The extra block should never contain more than 1 block here
128*0a437795SPablo de Lara                 assert(ctx->partial_block_buffer_length <= ISAL_SHA256_BLOCK_SIZE);
1296df3ef80SGreg Tucker 
1306df3ef80SGreg Tucker                 // If the extra block buffer contains exactly 1 block, it can be hashed.
131*0a437795SPablo de Lara                 if (ctx->partial_block_buffer_length >= ISAL_SHA256_BLOCK_SIZE) {
1326df3ef80SGreg Tucker                         ctx->partial_block_buffer_length = 0;
1336df3ef80SGreg Tucker 
1346df3ef80SGreg Tucker                         ctx->job.buffer = ctx->partial_block_buffer;
1356df3ef80SGreg Tucker                         ctx->job.len = 1;
136*0a437795SPablo de Lara                         ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_avx(&mgr->mgr,
137*0a437795SPablo de Lara                                                                                  &ctx->job);
1386df3ef80SGreg Tucker                 }
1396df3ef80SGreg Tucker         }
1406df3ef80SGreg Tucker 
1416df3ef80SGreg Tucker         return sha256_ctx_mgr_resubmit(mgr, ctx);
1426df3ef80SGreg Tucker }
1436df3ef80SGreg Tucker 
144*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *
_sha256_ctx_mgr_flush_avx(ISAL_SHA256_HASH_CTX_MGR * mgr)145*0a437795SPablo de Lara _sha256_ctx_mgr_flush_avx(ISAL_SHA256_HASH_CTX_MGR *mgr)
1466df3ef80SGreg Tucker {
147*0a437795SPablo de Lara         ISAL_SHA256_HASH_CTX *ctx;
1486df3ef80SGreg Tucker 
1496df3ef80SGreg Tucker         while (1) {
150*0a437795SPablo de Lara                 ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_flush_avx(&mgr->mgr);
1516df3ef80SGreg Tucker 
1526df3ef80SGreg Tucker                 // If flush returned 0, there are no more jobs in flight.
1536df3ef80SGreg Tucker                 if (!ctx)
1546df3ef80SGreg Tucker                         return NULL;
1556df3ef80SGreg Tucker 
1566df3ef80SGreg Tucker                 // If flush returned a job, verify that it is safe to return to the user.
1576df3ef80SGreg Tucker                 // If it is not ready, resubmit the job to finish processing.
1586df3ef80SGreg Tucker                 ctx = sha256_ctx_mgr_resubmit(mgr, ctx);
1596df3ef80SGreg Tucker 
1606df3ef80SGreg Tucker                 // If sha256_ctx_mgr_resubmit returned a job, it is ready to be returned.
1616df3ef80SGreg Tucker                 if (ctx)
1626df3ef80SGreg Tucker                         return ctx;
1636df3ef80SGreg Tucker 
164*0a437795SPablo de Lara                 // Otherwise, all jobs currently being managed by the ISAL_SHA256_HASH_CTX_MGR still
165*0a437795SPablo de Lara                 // need processing. Loop.
1666df3ef80SGreg Tucker         }
1676df3ef80SGreg Tucker }
1686df3ef80SGreg Tucker 
169*0a437795SPablo de Lara static ISAL_SHA256_HASH_CTX *
sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR * mgr,ISAL_SHA256_HASH_CTX * ctx)170*0a437795SPablo de Lara sha256_ctx_mgr_resubmit(ISAL_SHA256_HASH_CTX_MGR *mgr, ISAL_SHA256_HASH_CTX *ctx)
1716df3ef80SGreg Tucker {
1726df3ef80SGreg Tucker         while (ctx) {
1738cb7fe78SPablo de Lara                 if (ctx->status & ISAL_HASH_CTX_STS_COMPLETE) {
1748cb7fe78SPablo de Lara                         ctx->status = ISAL_HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
1756df3ef80SGreg Tucker                         return ctx;
1766df3ef80SGreg Tucker                 }
1776df3ef80SGreg Tucker                 // If the extra blocks are empty, begin hashing what remains in the user's buffer.
1786df3ef80SGreg Tucker                 if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
1796df3ef80SGreg Tucker                         const void *buffer = ctx->incoming_buffer;
1806df3ef80SGreg Tucker                         uint32_t len = ctx->incoming_buffer_length;
1816df3ef80SGreg Tucker 
1826df3ef80SGreg Tucker                         // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
183*0a437795SPablo de Lara                         uint32_t copy_len = len & (ISAL_SHA256_BLOCK_SIZE - 1);
1846df3ef80SGreg Tucker 
1856df3ef80SGreg Tucker                         if (copy_len) {
1866df3ef80SGreg Tucker                                 len -= copy_len;
1876df3ef80SGreg Tucker                                 memcpy_varlen(ctx->partial_block_buffer,
1886df3ef80SGreg Tucker                                               ((const char *) buffer + len), copy_len);
1896df3ef80SGreg Tucker                                 ctx->partial_block_buffer_length = copy_len;
1906df3ef80SGreg Tucker                         }
1916df3ef80SGreg Tucker 
1926df3ef80SGreg Tucker                         ctx->incoming_buffer_length = 0;
1936df3ef80SGreg Tucker 
1946df3ef80SGreg Tucker                         // len should be a multiple of the block size now
195*0a437795SPablo de Lara                         assert((len % ISAL_SHA256_BLOCK_SIZE) == 0);
1966df3ef80SGreg Tucker 
1976df3ef80SGreg Tucker                         // Set len to the number of blocks to be hashed in the user's buffer
198*0a437795SPablo de Lara                         len >>= ISAL_SHA256_LOG2_BLOCK_SIZE;
1996df3ef80SGreg Tucker 
2006df3ef80SGreg Tucker                         if (len) {
2016df3ef80SGreg Tucker                                 ctx->job.buffer = (uint8_t *) buffer;
2026df3ef80SGreg Tucker                                 ctx->job.len = len;
203*0a437795SPablo de Lara                                 ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_avx(&mgr->mgr,
2046df3ef80SGreg Tucker                                                                                          &ctx->job);
2056df3ef80SGreg Tucker                                 continue;
2066df3ef80SGreg Tucker                         }
2076df3ef80SGreg Tucker                 }
2086df3ef80SGreg Tucker                 // If the extra blocks are not empty, then we are either on the last block(s)
2096df3ef80SGreg Tucker                 // or we need more user input before continuing.
2108cb7fe78SPablo de Lara                 if (ctx->status & ISAL_HASH_CTX_STS_LAST) {
2116df3ef80SGreg Tucker                         uint8_t *buf = ctx->partial_block_buffer;
2126df3ef80SGreg Tucker                         uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
2136df3ef80SGreg Tucker 
2148cb7fe78SPablo de Lara                         ctx->status = (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
2158cb7fe78SPablo de Lara                                                            ISAL_HASH_CTX_STS_COMPLETE);
2166df3ef80SGreg Tucker                         ctx->job.buffer = buf;
2176df3ef80SGreg Tucker                         ctx->job.len = (uint32_t) n_extra_blocks;
218*0a437795SPablo de Lara                         ctx = (ISAL_SHA256_HASH_CTX *) _sha256_mb_mgr_submit_avx(&mgr->mgr,
219*0a437795SPablo de Lara                                                                                  &ctx->job);
2206df3ef80SGreg Tucker                         continue;
2216df3ef80SGreg Tucker                 }
2226df3ef80SGreg Tucker 
2236df3ef80SGreg Tucker                 if (ctx)
2248cb7fe78SPablo de Lara                         ctx->status = ISAL_HASH_CTX_STS_IDLE;
2256df3ef80SGreg Tucker                 return ctx;
2266df3ef80SGreg Tucker         }
2276df3ef80SGreg Tucker 
2286df3ef80SGreg Tucker         return NULL;
2296df3ef80SGreg Tucker }
2306df3ef80SGreg Tucker 
2319ba6f238SMarcel Cornu static inline void
hash_init_digest(ISAL_SHA256_WORD_T * digest)232*0a437795SPablo de Lara hash_init_digest(ISAL_SHA256_WORD_T *digest)
2336df3ef80SGreg Tucker {
234*0a437795SPablo de Lara         static const ISAL_SHA256_WORD_T hash_initial_digest[ISAL_SHA256_DIGEST_NWORDS] = {
235*0a437795SPablo de Lara                 ISAL_SHA256_INITIAL_DIGEST
2369ba6f238SMarcel Cornu         };
2376df3ef80SGreg Tucker         memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
2386df3ef80SGreg Tucker }
2396df3ef80SGreg Tucker 
2409ba6f238SMarcel Cornu static inline uint32_t
hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2],uint64_t total_len)241*0a437795SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA256_BLOCK_SIZE * 2], uint64_t total_len)
2426df3ef80SGreg Tucker {
243*0a437795SPablo de Lara         uint32_t i = (uint32_t) (total_len & (ISAL_SHA256_BLOCK_SIZE - 1));
2446df3ef80SGreg Tucker 
245*0a437795SPablo de Lara         memclr_fixedlen(&padblock[i], ISAL_SHA256_BLOCK_SIZE);
2466df3ef80SGreg Tucker         padblock[i] = 0x80;
2476df3ef80SGreg Tucker 
2486df3ef80SGreg Tucker         // Move i to the end of either 1st or 2nd extra block depending on length
249*0a437795SPablo de Lara         i += ((ISAL_SHA256_BLOCK_SIZE - 1) &
250*0a437795SPablo de Lara               (0 - (total_len + ISAL_SHA256_PADLENGTHFIELD_SIZE + 1))) +
251*0a437795SPablo de Lara              1 + ISAL_SHA256_PADLENGTHFIELD_SIZE;
2526df3ef80SGreg Tucker 
253*0a437795SPablo de Lara #if ISAL_SHA256_PADLENGTHFIELD_SIZE == 16
2546df3ef80SGreg Tucker         *((uint64_t *) &padblock[i - 16]) = 0;
2556df3ef80SGreg Tucker #endif
2566df3ef80SGreg Tucker 
257e3f7d4fbSUlrich Weigand         *((uint64_t *) &padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
2586df3ef80SGreg Tucker 
259*0a437795SPablo de Lara         return i >> ISAL_SHA256_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
2606df3ef80SGreg Tucker }
2616df3ef80SGreg Tucker 
2626df3ef80SGreg Tucker struct slver {
2636df3ef80SGreg Tucker         uint16_t snum;
2646df3ef80SGreg Tucker         uint8_t ver;
2656df3ef80SGreg Tucker         uint8_t core;
2666df3ef80SGreg Tucker };
2672fb85107SPablo de Lara struct slver _sha256_ctx_mgr_init_avx_slver_02020154;
2682fb85107SPablo de Lara struct slver _sha256_ctx_mgr_init_avx_slver = { 0x0154, 0x02, 0x02 };
2696df3ef80SGreg Tucker 
2702fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_avx_slver_02020155;
2712fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_avx_slver = { 0x0155, 0x02, 0x02 };
2726df3ef80SGreg Tucker 
2732fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_avx_slver_02020156;
2742fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_avx_slver = { 0x0156, 0x02, 0x02 };
275a6dc8696SGreg Tucker 
276a6dc8696SGreg Tucker #if defined(__clang__)
277a6dc8696SGreg Tucker #pragma clang attribute pop
278a6dc8696SGreg Tucker #endif
279