1
// Copyright (c) 2016-2020 The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4

            
5
#include <crypto/siphash.h>
6

            
7
5376
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
8

            
9
896
#define SIPROUND do { \
10
896
    v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
11
896
    v0 = ROTL(v0, 32); \
12
896
    v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
13
896
    v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
14
896
    v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
15
896
    v2 = ROTL(v2, 32); \
16
896
} while (0)
17

            
18
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
19
112
{
20
112
    v[0] = 0x736f6d6570736575ULL ^ k0;
21
112
    v[1] = 0x646f72616e646f6dULL ^ k1;
22
112
    v[2] = 0x6c7967656e657261ULL ^ k0;
23
112
    v[3] = 0x7465646279746573ULL ^ k1;
24
112
    count = 0;
25
112
    tmp = 0;
26
112
}
27

            
28
CSipHasher& CSipHasher::Write(uint64_t data)
29
112
{
30
112
    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
31

            
32
112
    assert(count % 8 == 0);
33

            
34
    v3 ^= data;
35
112
    SIPROUND;
36
112
    SIPROUND;
37
112
    v0 ^= data;
38

            
39
112
    v[0] = v0;
40
112
    v[1] = v1;
41
112
    v[2] = v2;
42
112
    v[3] = v3;
43

            
44
112
    count += 8;
45
112
    return *this;
46
112
}
47

            
48
CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
49
{
50
    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
51
    uint64_t t = tmp;
52
    uint8_t c = count;
53

            
54
    while (size--) {
55
        t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
56
        c++;
57
        if ((c & 7) == 0) {
58
            v3 ^= t;
59
            SIPROUND;
60
            SIPROUND;
61
            v0 ^= t;
62
            t = 0;
63
        }
64
    }
65

            
66
    v[0] = v0;
67
    v[1] = v1;
68
    v[2] = v2;
69
    v[3] = v3;
70
    count = c;
71
    tmp = t;
72

            
73
    return *this;
74
}
75

            
76
uint64_t CSipHasher::Finalize() const
77
112
{
78
112
    uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
79

            
80
112
    uint64_t t = tmp | (((uint64_t)count) << 56);
81

            
82
112
    v3 ^= t;
83
112
    SIPROUND;
84
112
    SIPROUND;
85
112
    v0 ^= t;
86
112
    v2 ^= 0xFF;
87
112
    SIPROUND;
88
112
    SIPROUND;
89
112
    SIPROUND;
90
112
    SIPROUND;
91
112
    return v0 ^ v1 ^ v2 ^ v3;
92
112
}
93

            
94
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
95
{
96
    /* Specialized implementation for efficiency */
97
    uint64_t d = val.GetUint64(0);
98

            
99
    uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
100
    uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
101
    uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
102
    uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
103

            
104
    SIPROUND;
105
    SIPROUND;
106
    v0 ^= d;
107
    d = val.GetUint64(1);
108
    v3 ^= d;
109
    SIPROUND;
110
    SIPROUND;
111
    v0 ^= d;
112
    d = val.GetUint64(2);
113
    v3 ^= d;
114
    SIPROUND;
115
    SIPROUND;
116
    v0 ^= d;
117
    d = val.GetUint64(3);
118
    v3 ^= d;
119
    SIPROUND;
120
    SIPROUND;
121
    v0 ^= d;
122
    v3 ^= ((uint64_t)4) << 59;
123
    SIPROUND;
124
    SIPROUND;
125
    v0 ^= ((uint64_t)4) << 59;
126
    v2 ^= 0xFF;
127
    SIPROUND;
128
    SIPROUND;
129
    SIPROUND;
130
    SIPROUND;
131
    return v0 ^ v1 ^ v2 ^ v3;
132
}
133

            
134
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
135
{
136
    /* Specialized implementation for efficiency */
137
    uint64_t d = val.GetUint64(0);
138

            
139
    uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
140
    uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
141
    uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
142
    uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
143

            
144
    SIPROUND;
145
    SIPROUND;
146
    v0 ^= d;
147
    d = val.GetUint64(1);
148
    v3 ^= d;
149
    SIPROUND;
150
    SIPROUND;
151
    v0 ^= d;
152
    d = val.GetUint64(2);
153
    v3 ^= d;
154
    SIPROUND;
155
    SIPROUND;
156
    v0 ^= d;
157
    d = val.GetUint64(3);
158
    v3 ^= d;
159
    SIPROUND;
160
    SIPROUND;
161
    v0 ^= d;
162
    d = (((uint64_t)36) << 56) | extra;
163
    v3 ^= d;
164
    SIPROUND;
165
    SIPROUND;
166
    v0 ^= d;
167
    v2 ^= 0xFF;
168
    SIPROUND;
169
    SIPROUND;
170
    SIPROUND;
171
    SIPROUND;
172
    return v0 ^ v1 ^ v2 ^ v3;
173
}