Coverage Report

Created: 2026-04-29 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/basic/siphash24.c
Line
Count
Source
1
/* SPDX-License-Identifier: CC0-1.0 */
2
3
/*
4
   SipHash reference C implementation
5
6
   Written in 2012 by
7
   Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
8
   Daniel J. Bernstein <djb@cr.yp.to>
9
10
   To the extent possible under law, the author(s) have dedicated all copyright
11
   and related and neighboring rights to this software to the public domain
12
   worldwide. This software is distributed without any warranty.
13
14
   You should have received a copy of the CC0 Public Domain Dedication along with
15
   this software. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
16
17
   (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
18
   (Refactored by Tom Gundersen to split up in several functions and follow systemd
19
    coding style)
20
*/
21
22
#include <stdio.h>
23
24
#include "siphash24.h"
25
#include "string-util.h"
26
#include "unaligned.h"
27
28
5.30G
static uint64_t rotate_left(uint64_t x, uint8_t b) {
29
5.30G
        assert(b < 64);
30
31
5.30G
        return (x << b) | (x >> (64 - b));
32
5.30G
}
33
34
884M
static void sipround(struct siphash *state) {
35
884M
        assert(state);
36
37
884M
        state->v0 += state->v1;
38
884M
        state->v1 = rotate_left(state->v1, 13);
39
884M
        state->v1 ^= state->v0;
40
884M
        state->v0 = rotate_left(state->v0, 32);
41
884M
        state->v2 += state->v3;
42
884M
        state->v3 = rotate_left(state->v3, 16);
43
884M
        state->v3 ^= state->v2;
44
884M
        state->v0 += state->v3;
45
884M
        state->v3 = rotate_left(state->v3, 21);
46
884M
        state->v3 ^= state->v0;
47
884M
        state->v2 += state->v1;
48
884M
        state->v1 = rotate_left(state->v1, 17);
49
884M
        state->v1 ^= state->v2;
50
884M
        state->v2 = rotate_left(state->v2, 32);
51
884M
}
52
53
101M
void siphash24_init(struct siphash *state, const uint8_t k[static 16]) {
54
101M
        uint64_t k0, k1;
55
56
101M
        assert(state);
57
101M
        assert(k);
58
59
101M
        k0 = unaligned_read_le64(k);
60
101M
        k1 = unaligned_read_le64(k + 8);
61
62
101M
        *state = (struct siphash) {
63
                /* "somepseudorandomlygeneratedbytes" */
64
101M
                .v0 = 0x736f6d6570736575ULL ^ k0,
65
101M
                .v1 = 0x646f72616e646f6dULL ^ k1,
66
101M
                .v2 = 0x6c7967656e657261ULL ^ k0,
67
101M
                .v3 = 0x7465646279746573ULL ^ k1,
68
101M
                .padding = 0,
69
101M
                .inlen = 0,
70
101M
        };
71
101M
}
72
73
156M
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
74
75
156M
        const uint8_t *in = ASSERT_PTR(_in);
76
156M
        const uint8_t *end = in + inlen;
77
156M
        size_t left = state->inlen & 7;
78
156M
        uint64_t m;
79
80
156M
        assert(state);
81
82
        /* Update total length */
83
156M
        state->inlen += inlen;
84
85
        /* If padding exists, fill it out */
86
156M
        if (left > 0) {
87
147M
                for ( ; in < end && left < 8; in ++, left ++)
88
96.4M
                        state->padding |= ((uint64_t) *in) << (left * 8);
89
90
50.6M
                if (in == end && left < 8)
91
                        /* We did not have enough input to fill out the padding completely */
92
36.5M
                        return;
93
94
#if ENABLE_DEBUG_SIPHASH
95
                printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
96
                printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
97
                printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
98
                printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
99
                printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
100
#endif
101
102
14.1M
                state->v3 ^= state->padding;
103
14.1M
                sipround(state);
104
14.1M
                sipround(state);
105
14.1M
                state->v0 ^= state->padding;
106
107
14.1M
                state->padding = 0;
108
14.1M
        }
109
110
120M
        end -= (state->inlen % sizeof(uint64_t));
111
112
245M
        for ( ; in < end; in += 8) {
113
125M
                m = unaligned_read_le64(in);
114
#if ENABLE_DEBUG_SIPHASH
115
                printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
116
                printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
117
                printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
118
                printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
119
                printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
120
#endif
121
125M
                state->v3 ^= m;
122
125M
                sipround(state);
123
125M
                sipround(state);
124
125M
                state->v0 ^= m;
125
125M
        }
126
127
120M
        left = state->inlen & 7;
128
120M
        switch (left) {
129
1.00M
                case 7:
130
1.00M
                        state->padding |= ((uint64_t) in[6]) << 48;
131
1.00M
                        _fallthrough_;
132
7.53M
                case 6:
133
7.53M
                        state->padding |= ((uint64_t) in[5]) << 40;
134
7.53M
                        _fallthrough_;
135
14.2M
                case 5:
136
14.2M
                        state->padding |= ((uint64_t) in[4]) << 32;
137
14.2M
                        _fallthrough_;
138
22.6M
                case 4:
139
22.6M
                        state->padding |= ((uint64_t) in[3]) << 24;
140
22.6M
                        _fallthrough_;
141
27.4M
                case 3:
142
27.4M
                        state->padding |= ((uint64_t) in[2]) << 16;
143
27.4M
                        _fallthrough_;
144
36.1M
                case 2:
145
36.1M
                        state->padding |= ((uint64_t) in[1]) <<  8;
146
36.1M
                        _fallthrough_;
147
60.9M
                case 1:
148
60.9M
                        state->padding |= ((uint64_t) in[0]);
149
60.9M
                        _fallthrough_;
150
120M
                case 0:
151
120M
                        break;
152
120M
        }
153
120M
}
154
155
2.86M
void siphash24_compress_string(const char *in, struct siphash *state) {
156
2.86M
        siphash24_compress_safe(in, strlen_ptr(in), state);
157
2.86M
}
158
159
101M
uint64_t siphash24_finalize(struct siphash *state) {
160
101M
        uint64_t b;
161
162
101M
        assert(state);
163
164
101M
        b = state->padding | (((uint64_t) state->inlen) << 56);
165
166
#if ENABLE_DEBUG_SIPHASH
167
        printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
168
        printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
169
        printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
170
        printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
171
        printf("(%3zu) padding   %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
172
#endif
173
174
101M
        state->v3 ^= b;
175
101M
        sipround(state);
176
101M
        sipround(state);
177
101M
        state->v0 ^= b;
178
179
#if ENABLE_DEBUG_SIPHASH
180
        printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
181
        printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
182
        printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
183
        printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
184
#endif
185
101M
        state->v2 ^= 0xff;
186
187
101M
        sipround(state);
188
101M
        sipround(state);
189
101M
        sipround(state);
190
101M
        sipround(state);
191
192
101M
        return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
193
101M
}
194
195
614k
uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) {
196
614k
        struct siphash state;
197
198
614k
        assert(in);
199
614k
        assert(k);
200
201
614k
        siphash24_init(&state, k);
202
614k
        siphash24_compress(in, inlen, &state);
203
204
614k
        return siphash24_finalize(&state);
205
614k
}
206
207
0
uint64_t siphash24_string(const char *s, const uint8_t k[static 16]) {
208
0
        return siphash24(s, strlen(s) + 1, k);
209
0
}