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("avx2"))), apply_to = function)
32a6dc8696SGreg Tucker #elif defined(__ICC)
33a6dc8696SGreg Tucker #pragma intel optimization_parameter target_arch = AVX2
34a6dc8696SGreg Tucker #elif defined(__ICL)
35a6dc8696SGreg Tucker #pragma[intel] optimization_parameter target_arch = AVX2
36a6dc8696SGreg Tucker #elif (__GNUC__ >= 5)
37a6dc8696SGreg Tucker #pragma GCC target("avx2")
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_avx512(ISAL_SHA256_HASH_CTX_MGR * mgr)57*0a437795SPablo de Lara _sha256_ctx_mgr_init_avx512(ISAL_SHA256_HASH_CTX_MGR *mgr)
586df3ef80SGreg Tucker {
593c423071SPablo de Lara _sha256_mb_mgr_init_avx512(&mgr->mgr);
606df3ef80SGreg Tucker }
616df3ef80SGreg Tucker
62*0a437795SPablo de Lara ISAL_SHA256_HASH_CTX *
_sha256_ctx_mgr_submit_avx512(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_avx512(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_avx512(&mgr->mgr,
1373c423071SPablo 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_avx512(ISAL_SHA256_HASH_CTX_MGR * mgr)145*0a437795SPablo de Lara _sha256_ctx_mgr_flush_avx512(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_avx512(&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_avx512(
204*0a437795SPablo de Lara &mgr->mgr, &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_avx512(&mgr->mgr,
2193c423071SPablo 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_avx512_slver_0600015a;
2682fb85107SPablo de Lara struct slver _sha256_ctx_mgr_init_avx512_slver = { 0x015a, 0x00, 0x06 };
2696df3ef80SGreg Tucker
2702fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_avx512_slver_0600015b;
2712fb85107SPablo de Lara struct slver _sha256_ctx_mgr_submit_avx512_slver = { 0x015b, 0x00, 0x06 };
2726df3ef80SGreg Tucker
2732fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_avx512_slver_0600015c;
2742fb85107SPablo de Lara struct slver _sha256_ctx_mgr_flush_avx512_slver = { 0x015c, 0x00, 0x06 };
2756df3ef80SGreg Tucker
276a6dc8696SGreg Tucker #if defined(__clang__)
277a6dc8696SGreg Tucker #pragma clang attribute pop
278a6dc8696SGreg Tucker #endif
279