Coverage Report

Created: 2026-10-28 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl35/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
611M
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34
#define U32TO8_LE(p, v)            \
35
22.0M
    (p)[0] = (uint8_t)((v));       \
36
22.0M
    (p)[1] = (uint8_t)((v) >> 8);  \
37
22.0M
    (p)[2] = (uint8_t)((v) >> 16); \
38
22.0M
    (p)[3] = (uint8_t)((v) >> 24);
39
40
#define U64TO8_LE(p, v)              \
41
11.0M
    U32TO8_LE((p), (uint32_t)((v))); \
42
11.0M
    U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44
#define U8TO64_LE(p) \
45
39.9M
    (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
46
47
#define SIPROUND           \
48
123M
    do {                   \
49
101M
        v0 += v1;          \
50
101M
        v1 = ROTL(v1, 13); \
51
101M
        v1 ^= v0;          \
52
101M
        v0 = ROTL(v0, 32); \
53
101M
        v2 += v3;          \
54
101M
        v3 = ROTL(v3, 16); \
55
101M
        v3 ^= v2;          \
56
101M
        v0 += v3;          \
57
101M
        v3 = ROTL(v3, 21); \
58
101M
        v3 ^= v0;          \
59
101M
        v2 += v1;          \
60
101M
        v1 = ROTL(v1, 17); \
61
101M
        v1 ^= v2;          \
62
101M
        v2 = ROTL(v2, 32); \
63
101M
    } while (0)
64
65
size_t SipHash_ctx_size(void)
66
0
{
67
0
    return sizeof(SIPHASH);
68
0
}
69
70
size_t SipHash_hash_size(SIPHASH *ctx)
71
5.36k
{
72
5.36k
    return ctx->hash_size;
73
5.36k
}
74
75
static size_t siphash_adjust_hash_size(size_t hash_size)
76
33.1M
{
77
33.1M
    if (hash_size == 0)
78
11.0M
        hash_size = SIPHASH_MAX_DIGEST_SIZE;
79
33.1M
    return hash_size;
80
33.1M
}
81
82
int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
83
11.0M
{
84
11.0M
    hash_size = siphash_adjust_hash_size(hash_size);
85
11.0M
    if (hash_size != SIPHASH_MIN_DIGEST_SIZE
86
217
        && hash_size != SIPHASH_MAX_DIGEST_SIZE)
87
55
        return 0;
88
89
    /*
90
     * It's possible that the key was set first.  If the hash size changes,
91
     * we need to adjust v1 (see SipHash_Init().
92
     */
93
94
    /* Start by adjusting the stored size, to make things easier */
95
11.0M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
96
97
    /* Now, adjust ctx->v1 if the old and the new size differ */
98
11.0M
    if ((size_t)ctx->hash_size != hash_size) {
99
11.0M
        ctx->v1 ^= 0xee;
100
11.0M
        ctx->hash_size = hash_size;
101
11.0M
    }
102
11.0M
    return 1;
103
11.0M
}
104
105
/* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
106
int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
107
11.0M
{
108
11.0M
    uint64_t k0 = U8TO64_LE(k);
109
11.0M
    uint64_t k1 = U8TO64_LE(k + 8);
110
111
    /* If the hash size wasn't set, i.e. is zero */
112
11.0M
    ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
113
114
11.0M
    if (drounds == 0)
115
11.0M
        drounds = SIPHASH_D_ROUNDS;
116
11.0M
    if (crounds == 0)
117
11.0M
        crounds = SIPHASH_C_ROUNDS;
118
119
11.0M
    ctx->crounds = crounds;
120
11.0M
    ctx->drounds = drounds;
121
122
11.0M
    ctx->len = 0;
123
11.0M
    ctx->total_inlen = 0;
124
125
11.0M
    ctx->v0 = 0x736f6d6570736575ULL ^ k0;
126
11.0M
    ctx->v1 = 0x646f72616e646f6dULL ^ k1;
127
11.0M
    ctx->v2 = 0x6c7967656e657261ULL ^ k0;
128
11.0M
    ctx->v3 = 0x7465646279746573ULL ^ k1;
129
130
11.0M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
131
2.71k
        ctx->v1 ^= 0xee;
132
133
11.0M
    return 1;
134
11.0M
}
135
136
void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
137
11.0M
{
138
11.0M
    uint64_t m;
139
11.0M
    const uint8_t *end;
140
11.0M
    int left;
141
11.0M
    unsigned int i;
142
11.0M
    uint64_t v0 = ctx->v0;
143
11.0M
    uint64_t v1 = ctx->v1;
144
11.0M
    uint64_t v2 = ctx->v2;
145
11.0M
    uint64_t v3 = ctx->v3;
146
147
11.0M
    ctx->total_inlen += inlen;
148
149
11.0M
    if (ctx->len) {
150
        /* deal with leavings */
151
90
        size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
152
153
        /* not enough to fill leavings */
154
90
        if (inlen < available) {
155
0
            memcpy(&ctx->leavings[ctx->len], in, inlen);
156
0
            ctx->len += inlen;
157
0
            return;
158
0
        }
159
160
        /* copy data into leavings and reduce input */
161
90
        memcpy(&ctx->leavings[ctx->len], in, available);
162
90
        inlen -= available;
163
90
        in += available;
164
165
        /* process leavings */
166
90
        m = U8TO64_LE(ctx->leavings);
167
90
        v3 ^= m;
168
270
        for (i = 0; i < ctx->crounds; ++i)
169
180
            SIPROUND;
170
90
        v0 ^= m;
171
90
    }
172
11.0M
    left = inlen & (SIPHASH_BLOCK_SIZE - 1); /* gets put into leavings */
173
11.0M
    end = in + inlen - left;
174
175
28.8M
    for (; in != end; in += 8) {
176
17.8M
        m = U8TO64_LE(in);
177
17.8M
        v3 ^= m;
178
53.4M
        for (i = 0; i < ctx->crounds; ++i)
179
35.6M
            SIPROUND;
180
17.8M
        v0 ^= m;
181
17.8M
    }
182
183
    /* save leavings and other ctx */
184
11.0M
    if (left)
185
5.71M
        memcpy(ctx->leavings, end, left);
186
11.0M
    ctx->len = left;
187
188
11.0M
    ctx->v0 = v0;
189
11.0M
    ctx->v1 = v1;
190
11.0M
    ctx->v2 = v2;
191
11.0M
    ctx->v3 = v3;
192
11.0M
}
193
194
int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
195
11.0M
{
196
    /* finalize hash */
197
11.0M
    unsigned int i;
198
11.0M
    uint64_t b = ctx->total_inlen << 56;
199
11.0M
    uint64_t v0 = ctx->v0;
200
11.0M
    uint64_t v1 = ctx->v1;
201
11.0M
    uint64_t v2 = ctx->v2;
202
11.0M
    uint64_t v3 = ctx->v3;
203
204
11.0M
    if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
205
0
        return 0;
206
207
11.0M
    switch (ctx->len) {
208
94.4k
    case 7:
209
94.4k
        b |= ((uint64_t)ctx->leavings[6]) << 48;
210
        /* fall through */
211
697k
    case 6:
212
697k
        b |= ((uint64_t)ctx->leavings[5]) << 40;
213
        /* fall through */
214
1.02M
    case 5:
215
1.02M
        b |= ((uint64_t)ctx->leavings[4]) << 32;
216
        /* fall through */
217
1.50M
    case 4:
218
1.50M
        b |= ((uint64_t)ctx->leavings[3]) << 24;
219
        /* fall through */
220
3.42M
    case 3:
221
3.42M
        b |= ((uint64_t)ctx->leavings[2]) << 16;
222
        /* fall through */
223
3.93M
    case 2:
224
3.93M
        b |= ((uint64_t)ctx->leavings[1]) << 8;
225
        /* fall through */
226
5.71M
    case 1:
227
5.71M
        b |= ((uint64_t)ctx->leavings[0]);
228
11.0M
    case 0:
229
11.0M
        break;
230
11.0M
    }
231
232
11.0M
    v3 ^= b;
233
33.1M
    for (i = 0; i < ctx->crounds; ++i)
234
22.0M
        SIPROUND;
235
11.0M
    v0 ^= b;
236
11.0M
    if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
237
2.68k
        v2 ^= 0xee;
238
11.0M
    else
239
11.0M
        v2 ^= 0xff;
240
55.1M
    for (i = 0; i < ctx->drounds; ++i)
241
44.1M
        SIPROUND;
242
11.0M
    b = v0 ^ v1 ^ v2 ^ v3;
243
11.0M
    U64TO8_LE(out, b);
244
11.0M
    if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
245
11.0M
        return 1;
246
2.68k
    v1 ^= 0xdd;
247
13.4k
    for (i = 0; i < ctx->drounds; ++i)
248
10.7k
        SIPROUND;
249
2.68k
    b = v0 ^ v1 ^ v2 ^ v3;
250
2.68k
    U64TO8_LE(out + 8, b);
251
2.68k
    return 1;
252
11.0M
}