Coverage Report

Created: 2026-07-25 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/mac/siphash/siphash.cpp
Line
Count
Source
1
/*
2
* SipHash
3
* (C) 2014,2015 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/siphash.h>
9
10
#include <botan/internal/fmt.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/rotate.h>
13
#include <botan/internal/stl_util.h>
14
15
namespace Botan {
16
17
namespace {
18
19
0
void SipRounds(uint64_t M, secure_vector<uint64_t>& V, size_t r) {
20
0
   uint64_t V0 = V[0], V1 = V[1], V2 = V[2], V3 = V[3];
21
22
0
   V3 ^= M;
23
0
   for(size_t i = 0; i != r; ++i) {
24
0
      V0 += V1;
25
0
      V2 += V3;
26
0
      V1 = rotl<13>(V1);
27
0
      V3 = rotl<16>(V3);
28
0
      V1 ^= V0;
29
0
      V3 ^= V2;
30
0
      V0 = rotl<32>(V0);
31
32
0
      V2 += V1;
33
0
      V0 += V3;
34
0
      V1 = rotl<17>(V1);
35
0
      V3 = rotl<21>(V3);
36
0
      V1 ^= V2;
37
0
      V3 ^= V0;
38
0
      V2 = rotl<32>(V2);
39
0
   }
40
0
   V0 ^= M;
41
42
0
   V[0] = V0;
43
0
   V[1] = V1;
44
0
   V[2] = V2;
45
0
   V[3] = V3;
46
0
}
47
48
}  // namespace
49
50
0
void SipHash::add_data(std::span<const uint8_t> input) {
51
0
   assert_key_material_set();
52
53
   // SipHash counts the message length mod 256
54
0
   m_words += static_cast<uint8_t>(input.size());
55
56
0
   BufferSlicer in(input);
57
58
0
   if(m_mbuf_pos) {
59
0
      while(!in.empty() && m_mbuf_pos != 8) {
60
0
         m_mbuf = (m_mbuf >> 8) | (static_cast<uint64_t>(in.take_byte()) << 56);
61
0
         ++m_mbuf_pos;
62
0
      }
63
64
0
      if(m_mbuf_pos == 8) {
65
0
         SipRounds(m_mbuf, m_V, m_C);
66
0
         m_mbuf_pos = 0;
67
0
         m_mbuf = 0;
68
0
      }
69
0
   }
70
71
0
   while(in.remaining() >= 8) {
72
0
      SipRounds(load_le<uint64_t>(in.take(8).data(), 0), m_V, m_C);
73
0
   }
74
75
0
   while(!in.empty()) {
76
0
      m_mbuf = (m_mbuf >> 8) | (static_cast<uint64_t>(in.take_byte()) << 56);
77
0
      m_mbuf_pos++;
78
0
   }
79
0
}
80
81
0
void SipHash::final_result(std::span<uint8_t> mac) {
82
0
   assert_key_material_set();
83
84
0
   if(m_mbuf_pos == 0) {
85
0
      m_mbuf = (static_cast<uint64_t>(m_words) << 56);
86
0
   } else if(m_mbuf_pos < 8) {
87
0
      m_mbuf = (m_mbuf >> (64 - m_mbuf_pos * 8)) | (static_cast<uint64_t>(m_words) << 56);
88
0
   }
89
90
0
   SipRounds(m_mbuf, m_V, m_C);
91
92
0
   m_V[2] ^= 0xFF;
93
0
   SipRounds(0, m_V, m_D);
94
95
0
   const uint64_t X = m_V[0] ^ m_V[1] ^ m_V[2] ^ m_V[3];
96
97
0
   store_le(X, mac.data());
98
99
0
   m_V[0] = m_K[0] ^ 0x736F6D6570736575;
100
0
   m_V[1] = m_K[1] ^ 0x646F72616E646F6D;
101
0
   m_V[2] = m_K[0] ^ 0x6C7967656E657261;
102
0
   m_V[3] = m_K[1] ^ 0x7465646279746573;
103
0
   m_mbuf = 0;
104
0
   m_mbuf_pos = 0;
105
0
   m_words = 0;
106
0
}
107
108
0
bool SipHash::has_keying_material() const {
109
0
   return !m_V.empty();
110
0
}
111
112
0
void SipHash::key_schedule(std::span<const uint8_t> key) {
113
0
   const uint64_t K0 = load_le<uint64_t>(key.data(), 0);
114
0
   const uint64_t K1 = load_le<uint64_t>(key.data(), 1);
115
116
0
   m_K.resize(2);
117
0
   m_K[0] = K0;
118
0
   m_K[1] = K1;
119
120
0
   m_V.resize(4);
121
0
   m_V[0] = m_K[0] ^ 0x736F6D6570736575;
122
0
   m_V[1] = m_K[1] ^ 0x646F72616E646F6D;
123
0
   m_V[2] = m_K[0] ^ 0x6C7967656E657261;
124
0
   m_V[3] = m_K[1] ^ 0x7465646279746573;
125
0
}
126
127
0
void SipHash::clear() {
128
0
   zap(m_K);
129
0
   zap(m_V);
130
0
   m_mbuf = 0;
131
0
   m_mbuf_pos = 0;
132
0
   m_words = 0;
133
0
}
134
135
0
std::string SipHash::name() const {
136
0
   return fmt("SipHash({},{})", m_C, m_D);
137
0
}
138
139
0
std::unique_ptr<MessageAuthenticationCode> SipHash::new_object() const {
140
0
   return std::make_unique<SipHash>(m_C, m_D);
141
0
}
142
143
}  // namespace Botan