Coverage Report

Created: 2025-11-16 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl30/crypto/siphash/siphash.c
Line
Count
Source
1
/*
2
 * Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
/* Based on https://131002.net/siphash C reference implementation */
11
/*
12
   SipHash reference C implementation
13
14
   Copyright (c) 2012-2016 Jean-Philippe Aumasson
15
   Copyright (c) 2012-2014 Daniel J. Bernstein
16
17
   To the extent possible under law, the author(s) have dedicated all copyright
18
   and related and neighboring rights to this software to the public domain
19
   worldwide. This software is distributed without any warranty.
20
21
   You should have received a copy of the CC0 Public Domain Dedication along
22
   with this software. If not, see
23
   <http://creativecommons.org/publicdomain/zero/1.0/>.
24
 */
25
26
#include <stdlib.h>
27
#include <string.h>
28
#include <openssl/crypto.h>
29
30
#include "crypto/siphash.h"
31
32
181M
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34
#define U32TO8_LE(p, v)                                                        \
35
9.16M
    (p)[0] = (uint8_t)((v));                                                   \
36
9.16M
    (p)[1] = (uint8_t)((v) >> 8);                                              \
37
9.16M
    (p)[2] = (uint8_t)((v) >> 16);                                             \
38
9.16M
    (p)[3] = (uint8_t)((v) >> 24);
39
40
#define U64TO8_LE(p, v)                                                        \
41
4.58M
    U32TO8_LE((p), (uint32_t)((v)));                                           \
42
4.58M
    U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44
#define U8TO64_LE(p)                                                           \
45
10.5M
    (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
46
10.5M
     ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
47
10.5M
     ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
48
10.5M
     ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
49
50
#define SIPROUND                                                               \
51
39.4M
    do {                                                                       \
52
30.2M
        v0 += v1;                                                              \
53
30.2M
        v1 = ROTL(v1, 13);                                                     \
54
30.2M
        v1 ^= v0;                                                              \
55
30.2M
        v0 = ROTL(v0, 32);                                                     \
56
30.2M
        v2 += v3;                                                              \
57
30.2M
        v3 = ROTL(v3, 16);                                                     \
58
30.2M
        v3 ^= v2;                                                              \
59
30.2M
        v0 += v3;                                                              \
60
30.2M
        v3 = ROTL(v3, 21);                                                     \
61
30.2M
        v3 ^= v0;                                                              \
62
30.2M
        v2 += v1;                                                              \
63
30.2M
        v1 = ROTL(v1, 17);                                                     \
64
30.2M
        v1 ^= v2;                                                              \
65
30.2M
        v2 = ROTL(v2, 32);                                                     \
66
30.2M
    } while (0)
67
68
size_t SipHash_ctx_size(void)
69
0
{
70
0
    return sizeof(SIPHASH);
71
0
}
72
73
size_t SipHash_hash_size(SIPHASH *ctx)
74
3.21k
{
75
3.21k
    return ctx->hash_size;
76
3.21k
}
77
78
static size_t siphash_adjust_hash_size(size_t hash_size)
79
13.7M
{
80
13.7M
    if (hash_size == 0)
81
4.58M
        hash_size = SIPHASH_MAX_DIGEST_SIZE;
82
13.7M
    return hash_size;
83
13.7M
}
84
85
int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
86
4.58M
{
87
4.58M
    hash_size = siphash_adjust_hash_size(hash_size);
88
4.58M
    if (hash_size != SIPHASH_MIN_DIGEST_SIZE
89
153
        && hash_size != SIPHASH_MAX_DIGEST_SIZE)
90
33
        return 0;
91
92
    /*
93
     * It's possible that the key was set first.  If the hash size changes,
94
     * we need to adjust v1 (see SipHash_Init().
95
     */
96
97
    /* Start by adjusting the stored size, to make things easier */
98
4.58M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
99
100
    /* Now, adjust ctx->v1 if the old and the new size differ */
101
4.58M
    if ((size_t)ctx->hash_size != hash_size) {
102
4.58M
        ctx->v1 ^= 0xee;
103
4.58M
        ctx->hash_size = hash_size;
104
4.58M
    }
105
4.58M
    return 1;
106
4.58M
}
107
108
/* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
109
int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
110
4.58M
{
111
4.58M
    uint64_t k0 = U8TO64_LE(k);
112
4.58M
    uint64_t k1 = U8TO64_LE(k + 8);
113
114
    /* If the hash size wasn't set, i.e. is zero */
115
4.58M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
116
117
4.58M
    if (drounds == 0)
118
4.58M
        drounds = SIPHASH_D_ROUNDS;
119
4.58M
    if (crounds == 0)
120
4.58M
        crounds = SIPHASH_C_ROUNDS;
121
122
4.58M
    ctx->crounds = crounds;
123
4.58M
    ctx->drounds = drounds;
124
125
4.58M
    ctx->len = 0;
126
4.58M
    ctx->total_inlen = 0;
127
128
4.58M
    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
129
4.58M
    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
130
4.58M
    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
131
4.58M
    ctx->v3 = 0x7465646279746573ULL ^ k1;
132
133
4.58M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
134
1.63k
        ctx->v1 ^= 0xee;
135
136
4.58M
    return 1;
137
4.58M
}
138
139
void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
140
4.58M
{
141
4.58M
    uint64_t m;
142
4.58M
    const uint8_t *end;
143
4.58M
    int left;
144
4.58M
    unsigned int i;
145
4.58M
    uint64_t v0 = ctx->v0;
146
4.58M
    uint64_t v1 = ctx->v1;
147
4.58M
    uint64_t v2 = ctx->v2;
148
4.58M
    uint64_t v3 = ctx->v3;
149
150
4.58M
    ctx->total_inlen += inlen;
151
152
4.58M
    if (ctx->len) {
153
        /* deal with leavings */
154
54
        size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
155
156
        /* not enough to fill leavings */
157
54
        if (inlen < available) {
158
0
            memcpy(&ctx->leavings[ctx->len], in, inlen);
159
0
            ctx->len += inlen;
160
0
            return;
161
0
        }
162
163
        /* copy data into leavings and reduce input */
164
54
        memcpy(&ctx->leavings[ctx->len], in, available);
165
54
        inlen -= available;
166
54
        in += available;
167
168
        /* process leavings */
169
54
        m = U8TO64_LE(ctx->leavings);
170
54
        v3 ^= m;
171
162
        for (i = 0; i < ctx->crounds; ++i)
172
108
            SIPROUND;
173
54
        v0 ^= m;
174
54
    }
175
4.58M
    left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
176
4.58M
    end = in + inlen - left;
177
178
5.95M
    for (; in != end; in += 8) {
179
1.37M
        m = U8TO64_LE(in);
180
1.37M
        v3 ^= m;
181
4.12M
        for (i = 0; i < ctx->crounds; ++i)
182
2.74M
            SIPROUND;
183
1.37M
        v0 ^= m;
184
1.37M
    }
185
186
    /* save leavings and other ctx */
187
4.58M
    if (left)
188
2.17M
        memcpy(ctx->leavings, end, left);
189
4.58M
    ctx->len = left;
190
191
4.58M
    ctx->v0 = v0;
192
4.58M
    ctx->v1 = v1;
193
4.58M
    ctx->v2 = v2;
194
4.58M
    ctx->v3 = v3;
195
4.58M
}
196
197
int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
198
4.58M
{
199
    /* finalize hash */
200
4.58M
    unsigned int i;
201
4.58M
    uint64_t b = ctx->total_inlen << 56;
202
4.58M
    uint64_t v0 = ctx->v0;
203
4.58M
    uint64_t v1 = ctx->v1;
204
4.58M
    uint64_t v2 = ctx->v2;
205
4.58M
    uint64_t v3 = ctx->v3;
206
207
4.58M
    if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
208
0
        return 0;
209
210
4.58M
    switch (ctx->len) {
211
41.3k
    case 7:
212
41.3k
        b |= ((uint64_t)ctx->leavings[6]) << 48;
213
        /* fall thru */
214
118k
    case 6:
215
118k
        b |= ((uint64_t)ctx->leavings[5]) << 40;
216
        /* fall thru */
217
282k
    case 5:
218
282k
        b |= ((uint64_t)ctx->leavings[4]) << 32;
219
        /* fall thru */
220
619k
    case 4:
221
619k
        b |= ((uint64_t)ctx->leavings[3]) << 24;
222
        /* fall thru */
223
1.50M
    case 3:
224
1.50M
        b |= ((uint64_t)ctx->leavings[2]) << 16;
225
        /* fall thru */
226
1.64M
    case 2:
227
1.64M
        b |= ((uint64_t)ctx->leavings[1]) <<  8;
228
        /* fall thru */
229
2.17M
    case 1:
230
2.17M
        b |= ((uint64_t)ctx->leavings[0]);
231
4.58M
    case 0:
232
4.58M
        break;
233
4.58M
    }
234
235
4.58M
    v3 ^= b;
236
13.7M
    for (i = 0; i < ctx->crounds; ++i)
237
9.16M
        SIPROUND;
238
4.58M
    v0 ^= b;
239
4.58M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
240
1.60k
        v2 ^= 0xee;
241
4.58M
    else
242
4.58M
        v2 ^= 0xff;
243
22.9M
    for (i = 0; i < ctx->drounds; ++i)
244
18.3M
        SIPROUND;
245
4.58M
    b = v0 ^ v1 ^ v2  ^ v3;
246
4.58M
    U64TO8_LE(out, b);
247
4.58M
    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
248
4.58M
        return 1;
249
1.60k
    v1 ^= 0xdd;
250
8.04k
    for (i = 0; i < ctx->drounds; ++i)
251
6.43k
        SIPROUND;
252
1.60k
    b = v0 ^ v1 ^ v2  ^ v3;
253
1.60k
    U64TO8_LE(out + 8, b);
254
1.60k
    return 1;
255
4.58M
}