Coverage Report

Created: 2026-10-06 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/freebl/ghash-x86.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#ifdef FREEBL_NO_DEPEND
6
#include "stubs.h"
7
#endif
8
#include "blapii.h"
9
#include "gcm.h"
10
#include "secerr.h"
11
12
#include <wmmintrin.h> /* clmul */
13
14
#define WRITE64(x, bytes)   \
15
0
    (bytes)[0] = (x) >> 56; \
16
0
    (bytes)[1] = (x) >> 48; \
17
0
    (bytes)[2] = (x) >> 40; \
18
0
    (bytes)[3] = (x) >> 32; \
19
0
    (bytes)[4] = (x) >> 24; \
20
0
    (bytes)[5] = (x) >> 16; \
21
0
    (bytes)[6] = (x) >> 8;  \
22
0
    (bytes)[7] = (x);
23
24
PRBool
25
platform_ghash_support()
26
0
{
27
0
    return clmul_support();
28
0
}
29
30
SECStatus
31
gcm_HashWrite_hw(gcmHashContext *ghash, unsigned char *outbuf)
32
0
{
33
0
    uint64_t tmp_out[2];
34
0
    _mm_storeu_si128((__m128i *)tmp_out, ghash->x);
35
    /* maxout must be larger than 16 byte (checked by the caller). */
36
0
    WRITE64(tmp_out[0], outbuf + 8);
37
0
    WRITE64(tmp_out[1], outbuf);
38
0
    return SECSuccess;
39
0
}
40
41
SECStatus
42
gcm_HashMult_hw(gcmHashContext *ghash, const unsigned char *buf,
43
                unsigned int count)
44
0
{
45
0
    size_t i;
46
0
    pre_align __m128i z_high post_align;
47
0
    pre_align __m128i z_low post_align;
48
0
    pre_align __m128i C post_align;
49
0
    pre_align __m128i D post_align;
50
0
    pre_align __m128i E post_align;
51
0
    pre_align __m128i F post_align;
52
0
    pre_align __m128i bin post_align;
53
0
    pre_align __m128i Ci post_align;
54
0
    pre_align __m128i tmp post_align;
55
56
0
    for (i = 0; i < count; i++, buf += 16) {
57
0
        bin = _mm_set_epi16(((uint16_t)buf[0] << 8) | buf[1],
58
0
                            ((uint16_t)buf[2] << 8) | buf[3],
59
0
                            ((uint16_t)buf[4] << 8) | buf[5],
60
0
                            ((uint16_t)buf[6] << 8) | buf[7],
61
0
                            ((uint16_t)buf[8] << 8) | buf[9],
62
0
                            ((uint16_t)buf[10] << 8) | buf[11],
63
0
                            ((uint16_t)buf[12] << 8) | buf[13],
64
0
                            ((uint16_t)buf[14] << 8) | buf[15]);
65
0
        Ci = _mm_xor_si128(bin, ghash->x);
66
67
        /* Do binary mult ghash->X = Ci * ghash->H. */
68
0
        C = _mm_clmulepi64_si128(Ci, ghash->h, 0x00);
69
0
        D = _mm_clmulepi64_si128(Ci, ghash->h, 0x11);
70
0
        E = _mm_clmulepi64_si128(Ci, ghash->h, 0x01);
71
0
        F = _mm_clmulepi64_si128(Ci, ghash->h, 0x10);
72
0
        tmp = _mm_xor_si128(E, F);
73
0
        z_high = _mm_xor_si128(tmp, _mm_slli_si128(D, 8));
74
0
        z_high = _mm_unpackhi_epi64(z_high, D);
75
0
        z_low = _mm_xor_si128(_mm_slli_si128(tmp, 8), C);
76
0
        z_low = _mm_unpackhi_epi64(_mm_slli_si128(C, 8), z_low);
77
78
        /* Shift one to the left (multiply by x) as gcm spec is stupid. */
79
0
        C = _mm_slli_si128(z_low, 8);
80
0
        E = _mm_srli_epi64(C, 63);
81
0
        D = _mm_slli_si128(z_high, 8);
82
0
        F = _mm_srli_epi64(D, 63);
83
        /* Carry over */
84
0
        C = _mm_srli_si128(z_low, 8);
85
0
        D = _mm_srli_epi64(C, 63);
86
0
        z_low = _mm_or_si128(_mm_slli_epi64(z_low, 1), E);
87
0
        z_high = _mm_or_si128(_mm_or_si128(_mm_slli_epi64(z_high, 1), F), D);
88
89
        /* Reduce */
90
0
        C = _mm_slli_si128(z_low, 8);
91
        /* D = z_low << 127 */
92
0
        D = _mm_slli_epi64(C, 63);
93
        /* E = z_low << 126 */
94
0
        E = _mm_slli_epi64(C, 62);
95
        /* F = z_low << 121 */
96
0
        F = _mm_slli_epi64(C, 57);
97
        /* z_low ^= (z_low << 127) ^ (z_low << 126) ^ (z_low << 121); */
98
0
        z_low = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(z_low, D), E), F);
99
0
        C = _mm_srli_si128(z_low, 8);
100
        /* D = z_low >> 1 */
101
0
        D = _mm_slli_epi64(C, 63);
102
0
        D = _mm_or_si128(_mm_srli_epi64(z_low, 1), D);
103
        /* E = z_low >> 2 */
104
0
        E = _mm_slli_epi64(C, 62);
105
0
        E = _mm_or_si128(_mm_srli_epi64(z_low, 2), E);
106
        /* F = z_low >> 7 */
107
0
        F = _mm_slli_epi64(C, 57);
108
0
        F = _mm_or_si128(_mm_srli_epi64(z_low, 7), F);
109
        /* ghash->x ^= z_low ^ (z_low >> 1) ^ (z_low >> 2) ^ (z_low >> 7); */
110
0
        ghash->x = _mm_xor_si128(_mm_xor_si128(
111
0
                                     _mm_xor_si128(_mm_xor_si128(z_high, z_low), D), E),
112
0
                                 F);
113
0
    }
114
0
    return SECSuccess;
115
0
}
116
117
SECStatus
118
gcm_HashInit_hw(gcmHashContext *ghash)
119
0
{
120
0
    ghash->ghash_mul = gcm_HashMult_hw;
121
0
    ghash->x = _mm_setzero_si128();
122
    /* MSVC requires __m64 to load epi64. */
123
0
    ghash->h = _mm_set_epi32(ghash->h_high >> 32, (uint32_t)ghash->h_high,
124
0
                             ghash->h_low >> 32, (uint32_t)ghash->h_low);
125
0
    ghash->hw = PR_TRUE;
126
0
    return SECSuccess;
127
0
}
128
129
SECStatus
130
gcm_HashZeroX_hw(gcmHashContext *ghash)
131
0
{
132
0
    ghash->x = _mm_setzero_si128();
133
0
    return SECSuccess;
134
0
}