xref: /isa-l_crypto/sha1_mb/sha1_ctx_sse.c (revision 8cb7fe780eac8ee5f1e0aa3ca37466e89c673ccd)
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 
3076c9379fSPablo de Lara #include "sha1_mb_internal.h"
316df3ef80SGreg Tucker #include "memcpy_inline.h"
3292aa5aa4SGreg Tucker #include "endian_helper.h"
336df3ef80SGreg Tucker 
346df3ef80SGreg Tucker #ifdef _MSC_VER
356df3ef80SGreg Tucker #include <intrin.h>
366df3ef80SGreg Tucker #define inline __inline
376df3ef80SGreg Tucker #endif
386df3ef80SGreg Tucker 
39868f05eaSMarcel Cornu static inline void
400106da91SPablo de Lara hash_init_digest(ISAL_SHA1_WORD_T *digest);
41868f05eaSMarcel Cornu static inline uint32_t
420106da91SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2], uint64_t total_len);
430106da91SPablo de Lara static ISAL_SHA1_HASH_CTX *
440106da91SPablo de Lara sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx);
456df3ef80SGreg Tucker 
46868f05eaSMarcel Cornu void
_sha1_ctx_mgr_init_sse(ISAL_SHA1_HASH_CTX_MGR * mgr)470106da91SPablo de Lara _sha1_ctx_mgr_init_sse(ISAL_SHA1_HASH_CTX_MGR *mgr)
486df3ef80SGreg Tucker {
4976c9379fSPablo de Lara         _sha1_mb_mgr_init_sse(&mgr->mgr);
506df3ef80SGreg Tucker }
516df3ef80SGreg Tucker 
520106da91SPablo de Lara ISAL_SHA1_HASH_CTX *
_sha1_ctx_mgr_submit_sse(ISAL_SHA1_HASH_CTX_MGR * mgr,ISAL_SHA1_HASH_CTX * ctx,const void * buffer,uint32_t len,ISAL_HASH_CTX_FLAG flags)530106da91SPablo de Lara _sha1_ctx_mgr_submit_sse(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx, const void *buffer,
54*8cb7fe78SPablo de Lara                          uint32_t len, ISAL_HASH_CTX_FLAG flags)
556df3ef80SGreg Tucker {
56*8cb7fe78SPablo de Lara         if (flags & (~ISAL_HASH_ENTIRE)) {
576df3ef80SGreg Tucker                 // User should not pass anything other than FIRST, UPDATE, or LAST
58*8cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_INVALID_FLAGS;
596df3ef80SGreg Tucker                 return ctx;
606df3ef80SGreg Tucker         }
616df3ef80SGreg Tucker 
62*8cb7fe78SPablo de Lara         if (ctx->status & ISAL_HASH_CTX_STS_PROCESSING) {
636df3ef80SGreg Tucker                 // Cannot submit to a currently processing job.
64*8cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_PROCESSING;
656df3ef80SGreg Tucker                 return ctx;
666df3ef80SGreg Tucker         }
676df3ef80SGreg Tucker 
68*8cb7fe78SPablo de Lara         if ((ctx->status & ISAL_HASH_CTX_STS_COMPLETE) && !(flags & ISAL_HASH_FIRST)) {
696df3ef80SGreg Tucker                 // Cannot update a finished job.
70*8cb7fe78SPablo de Lara                 ctx->error = ISAL_HASH_CTX_ERROR_ALREADY_COMPLETED;
716df3ef80SGreg Tucker                 return ctx;
726df3ef80SGreg Tucker         }
736df3ef80SGreg Tucker 
74*8cb7fe78SPablo de Lara         if (flags & ISAL_HASH_FIRST) {
756df3ef80SGreg Tucker                 // Init digest
766df3ef80SGreg Tucker                 hash_init_digest(ctx->job.result_digest);
776df3ef80SGreg Tucker 
786df3ef80SGreg Tucker                 // Reset byte counter
796df3ef80SGreg Tucker                 ctx->total_length = 0;
806df3ef80SGreg Tucker 
816df3ef80SGreg Tucker                 // Clear extra blocks
826df3ef80SGreg Tucker                 ctx->partial_block_buffer_length = 0;
836df3ef80SGreg Tucker         }
846df3ef80SGreg Tucker         // If we made it here, there were no errors during this call to submit
85*8cb7fe78SPablo de Lara         ctx->error = ISAL_HASH_CTX_ERROR_NONE;
866df3ef80SGreg Tucker 
876df3ef80SGreg Tucker         // Store buffer ptr info from user
886df3ef80SGreg Tucker         ctx->incoming_buffer = buffer;
896df3ef80SGreg Tucker         ctx->incoming_buffer_length = len;
906df3ef80SGreg Tucker 
916df3ef80SGreg Tucker         // Store the user's request flags and mark this ctx as currently being processed.
92*8cb7fe78SPablo de Lara         ctx->status = (flags & ISAL_HASH_LAST) ? (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
93*8cb7fe78SPablo de Lara                                                                       ISAL_HASH_CTX_STS_LAST)
94*8cb7fe78SPablo de Lara                                                : ISAL_HASH_CTX_STS_PROCESSING;
956df3ef80SGreg Tucker 
966df3ef80SGreg Tucker         // Advance byte counter
976df3ef80SGreg Tucker         ctx->total_length += len;
986df3ef80SGreg Tucker 
99868f05eaSMarcel Cornu         // If there is anything currently buffered in the extra blocks, append to it until it
100868f05eaSMarcel Cornu         // contains a whole block. Or if the user's buffer contains less than a whole block, append
101868f05eaSMarcel Cornu         // as much as possible to the extra block.
1020106da91SPablo de Lara         if ((ctx->partial_block_buffer_length) | (len < ISAL_SHA1_BLOCK_SIZE)) {
1036df3ef80SGreg Tucker                 // Compute how many bytes to copy from user buffer into extra block
1040106da91SPablo de Lara                 uint32_t copy_len = ISAL_SHA1_BLOCK_SIZE - ctx->partial_block_buffer_length;
1056df3ef80SGreg Tucker                 if (len < copy_len)
1066df3ef80SGreg Tucker                         copy_len = len;
1076df3ef80SGreg Tucker 
1086df3ef80SGreg Tucker                 if (copy_len) {
1096df3ef80SGreg Tucker                         // Copy and update relevant pointers and counters
110868f05eaSMarcel Cornu                         memcpy_varlen(&ctx->partial_block_buffer[ctx->partial_block_buffer_length],
111868f05eaSMarcel Cornu                                       buffer, copy_len);
1126df3ef80SGreg Tucker 
1136df3ef80SGreg Tucker                         ctx->partial_block_buffer_length += copy_len;
1146df3ef80SGreg Tucker                         ctx->incoming_buffer = (const void *) ((const char *) buffer + copy_len);
1156df3ef80SGreg Tucker                         ctx->incoming_buffer_length = len - copy_len;
1166df3ef80SGreg Tucker                 }
1176df3ef80SGreg Tucker                 // The extra block should never contain more than 1 block here
1180106da91SPablo de Lara                 assert(ctx->partial_block_buffer_length <= ISAL_SHA1_BLOCK_SIZE);
1196df3ef80SGreg Tucker 
1206df3ef80SGreg Tucker                 // If the extra block buffer contains exactly 1 block, it can be hashed.
1210106da91SPablo de Lara                 if (ctx->partial_block_buffer_length >= ISAL_SHA1_BLOCK_SIZE) {
1226df3ef80SGreg Tucker                         ctx->partial_block_buffer_length = 0;
1236df3ef80SGreg Tucker 
1246df3ef80SGreg Tucker                         ctx->job.buffer = ctx->partial_block_buffer;
1256df3ef80SGreg Tucker                         ctx->job.len = 1;
1266df3ef80SGreg Tucker 
1270106da91SPablo de Lara                         ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr, &ctx->job);
1286df3ef80SGreg Tucker                 }
1296df3ef80SGreg Tucker         }
1306df3ef80SGreg Tucker 
1316df3ef80SGreg Tucker         return sha1_ctx_mgr_resubmit(mgr, ctx);
1326df3ef80SGreg Tucker }
1336df3ef80SGreg Tucker 
1340106da91SPablo de Lara ISAL_SHA1_HASH_CTX *
_sha1_ctx_mgr_flush_sse(ISAL_SHA1_HASH_CTX_MGR * mgr)1350106da91SPablo de Lara _sha1_ctx_mgr_flush_sse(ISAL_SHA1_HASH_CTX_MGR *mgr)
1366df3ef80SGreg Tucker {
1370106da91SPablo de Lara         ISAL_SHA1_HASH_CTX *ctx;
1386df3ef80SGreg Tucker 
1396df3ef80SGreg Tucker         while (1) {
1400106da91SPablo de Lara                 ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_flush_sse(&mgr->mgr);
1416df3ef80SGreg Tucker 
1426df3ef80SGreg Tucker                 // If flush returned 0, there are no more jobs in flight.
1436df3ef80SGreg Tucker                 if (!ctx)
1446df3ef80SGreg Tucker                         return NULL;
1456df3ef80SGreg Tucker 
1466df3ef80SGreg Tucker                 // If flush returned a job, verify that it is safe to return to the user.
1476df3ef80SGreg Tucker                 // If it is not ready, resubmit the job to finish processing.
1486df3ef80SGreg Tucker                 ctx = sha1_ctx_mgr_resubmit(mgr, ctx);
1496df3ef80SGreg Tucker 
1506df3ef80SGreg Tucker                 // If sha1_ctx_mgr_resubmit returned a job, it is ready to be returned.
1516df3ef80SGreg Tucker                 if (ctx)
1526df3ef80SGreg Tucker                         return ctx;
1536df3ef80SGreg Tucker 
1540106da91SPablo de Lara                 // Otherwise, all jobs currently being managed by the ISAL_SHA1_HASH_CTX_MGR still
1550106da91SPablo de Lara                 // need processing. Loop.
1566df3ef80SGreg Tucker         }
1576df3ef80SGreg Tucker }
1586df3ef80SGreg Tucker 
1590106da91SPablo de Lara static ISAL_SHA1_HASH_CTX *
sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR * mgr,ISAL_SHA1_HASH_CTX * ctx)1600106da91SPablo de Lara sha1_ctx_mgr_resubmit(ISAL_SHA1_HASH_CTX_MGR *mgr, ISAL_SHA1_HASH_CTX *ctx)
1616df3ef80SGreg Tucker {
1626df3ef80SGreg Tucker         while (ctx) {
1636df3ef80SGreg Tucker 
164*8cb7fe78SPablo de Lara                 if (ctx->status & ISAL_HASH_CTX_STS_COMPLETE) {
165*8cb7fe78SPablo de Lara                         ctx->status = ISAL_HASH_CTX_STS_COMPLETE; // Clear PROCESSING bit
1666df3ef80SGreg Tucker                         return ctx;
1676df3ef80SGreg Tucker                 }
1686df3ef80SGreg Tucker                 // If the extra blocks are empty, begin hashing what remains in the user's buffer.
1696df3ef80SGreg Tucker                 if (ctx->partial_block_buffer_length == 0 && ctx->incoming_buffer_length) {
1706df3ef80SGreg Tucker                         const void *buffer = ctx->incoming_buffer;
1716df3ef80SGreg Tucker                         uint32_t len = ctx->incoming_buffer_length;
1726df3ef80SGreg Tucker 
1736df3ef80SGreg Tucker                         // Only entire blocks can be hashed. Copy remainder to extra blocks buffer.
1740106da91SPablo de Lara                         uint32_t copy_len = len & (ISAL_SHA1_BLOCK_SIZE - 1);
1756df3ef80SGreg Tucker 
1766df3ef80SGreg Tucker                         if (copy_len) {
1776df3ef80SGreg Tucker                                 len -= copy_len;
1786df3ef80SGreg Tucker                                 memcpy_varlen(ctx->partial_block_buffer,
1796df3ef80SGreg Tucker                                               ((const char *) buffer + len), copy_len);
1806df3ef80SGreg Tucker                                 ctx->partial_block_buffer_length = copy_len;
1816df3ef80SGreg Tucker                         }
1826df3ef80SGreg Tucker 
1836df3ef80SGreg Tucker                         ctx->incoming_buffer_length = 0;
1846df3ef80SGreg Tucker 
1856df3ef80SGreg Tucker                         // len should be a multiple of the block size now
1860106da91SPablo de Lara                         assert((len % ISAL_SHA1_BLOCK_SIZE) == 0);
1876df3ef80SGreg Tucker 
1886df3ef80SGreg Tucker                         // Set len to the number of blocks to be hashed in the user's buffer
1890106da91SPablo de Lara                         len >>= ISAL_SHA1_LOG2_BLOCK_SIZE;
1906df3ef80SGreg Tucker 
1916df3ef80SGreg Tucker                         if (len) {
1926df3ef80SGreg Tucker                                 ctx->job.buffer = (uint8_t *) buffer;
1936df3ef80SGreg Tucker                                 ctx->job.len = len;
1940106da91SPablo de Lara                                 ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr,
1956df3ef80SGreg Tucker                                                                                      &ctx->job);
1966df3ef80SGreg Tucker                                 continue;
1976df3ef80SGreg Tucker                         }
1986df3ef80SGreg Tucker                 }
1996df3ef80SGreg Tucker                 // If the extra blocks are not empty, then we are either on the last block(s)
2006df3ef80SGreg Tucker                 // or we need more user input before continuing.
201*8cb7fe78SPablo de Lara                 if (ctx->status & ISAL_HASH_CTX_STS_LAST) {
2026df3ef80SGreg Tucker                         uint8_t *buf = ctx->partial_block_buffer;
2036df3ef80SGreg Tucker                         uint32_t n_extra_blocks = hash_pad(buf, ctx->total_length);
2046df3ef80SGreg Tucker 
205*8cb7fe78SPablo de Lara                         ctx->status = (ISAL_HASH_CTX_STS) (ISAL_HASH_CTX_STS_PROCESSING |
206*8cb7fe78SPablo de Lara                                                            ISAL_HASH_CTX_STS_COMPLETE);
2076df3ef80SGreg Tucker                         ctx->job.buffer = buf;
2086df3ef80SGreg Tucker                         ctx->job.len = (uint32_t) n_extra_blocks;
2090106da91SPablo de Lara                         ctx = (ISAL_SHA1_HASH_CTX *) _sha1_mb_mgr_submit_sse(&mgr->mgr, &ctx->job);
2106df3ef80SGreg Tucker                         continue;
2116df3ef80SGreg Tucker                 }
2126df3ef80SGreg Tucker 
2136df3ef80SGreg Tucker                 if (ctx)
214*8cb7fe78SPablo de Lara                         ctx->status = ISAL_HASH_CTX_STS_IDLE;
2156df3ef80SGreg Tucker                 return ctx;
2166df3ef80SGreg Tucker         }
2176df3ef80SGreg Tucker 
2186df3ef80SGreg Tucker         return NULL;
2196df3ef80SGreg Tucker }
2206df3ef80SGreg Tucker 
221868f05eaSMarcel Cornu static inline void
hash_init_digest(ISAL_SHA1_WORD_T * digest)2220106da91SPablo de Lara hash_init_digest(ISAL_SHA1_WORD_T *digest)
2236df3ef80SGreg Tucker {
2240106da91SPablo de Lara         static const ISAL_SHA1_WORD_T hash_initial_digest[ISAL_SHA1_DIGEST_NWORDS] = {
2250106da91SPablo de Lara                 ISAL_SHA1_INITIAL_DIGEST
2260106da91SPablo de Lara         };
2276df3ef80SGreg Tucker         memcpy_fixedlen(digest, hash_initial_digest, sizeof(hash_initial_digest));
2286df3ef80SGreg Tucker }
2296df3ef80SGreg Tucker 
230868f05eaSMarcel Cornu static inline uint32_t
hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2],uint64_t total_len)2310106da91SPablo de Lara hash_pad(uint8_t padblock[ISAL_SHA1_BLOCK_SIZE * 2], uint64_t total_len)
2326df3ef80SGreg Tucker {
2330106da91SPablo de Lara         uint32_t i = (uint32_t) (total_len & (ISAL_SHA1_BLOCK_SIZE - 1));
2346df3ef80SGreg Tucker 
2350106da91SPablo de Lara         memclr_fixedlen(&padblock[i], ISAL_SHA1_BLOCK_SIZE);
2366df3ef80SGreg Tucker         padblock[i] = 0x80;
2376df3ef80SGreg Tucker 
2386df3ef80SGreg Tucker         // Move i to the end of either 1st or 2nd extra block depending on length
2390106da91SPablo de Lara         i += ((ISAL_SHA1_BLOCK_SIZE - 1) & (0 - (total_len + ISAL_SHA1_PADLENGTHFIELD_SIZE + 1))) +
2400106da91SPablo de Lara              1 + ISAL_SHA1_PADLENGTHFIELD_SIZE;
2416df3ef80SGreg Tucker 
2420106da91SPablo de Lara #if ISAL_SHA1_PADLENGTHFIELD_SIZE == 16
2436df3ef80SGreg Tucker         *((uint64_t *) &padblock[i - 16]) = 0;
2446df3ef80SGreg Tucker #endif
2456df3ef80SGreg Tucker 
246e3f7d4fbSUlrich Weigand         *((uint64_t *) &padblock[i - 8]) = to_be64((uint64_t) total_len << 3);
2476df3ef80SGreg Tucker 
2480106da91SPablo de Lara         return i >> ISAL_SHA1_LOG2_BLOCK_SIZE; // Number of extra blocks to hash
2496df3ef80SGreg Tucker }
2506df3ef80SGreg Tucker 
2516df3ef80SGreg Tucker struct slver {
2526df3ef80SGreg Tucker         uint16_t snum;
2536df3ef80SGreg Tucker         uint8_t ver;
2546df3ef80SGreg Tucker         uint8_t core;
2556df3ef80SGreg Tucker };
2563113c339SPablo de Lara struct slver _sha1_ctx_mgr_init_sse_slver_00020139;
2573113c339SPablo de Lara struct slver _sha1_ctx_mgr_init_sse_slver = { 0x0139, 0x02, 0x00 };
2586df3ef80SGreg Tucker 
2593113c339SPablo de Lara struct slver _sha1_ctx_mgr_submit_sse_slver_00020140;
2603113c339SPablo de Lara struct slver _sha1_ctx_mgr_submit_sse_slver = { 0x0140, 0x02, 0x00 };
2616df3ef80SGreg Tucker 
2623113c339SPablo de Lara struct slver _sha1_ctx_mgr_flush_sse_slver_00020141;
2633113c339SPablo de Lara struct slver _sha1_ctx_mgr_flush_sse_slver = { 0x0141, 0x02, 0x00 };
264