/src/botan/build/include/internal/botan/internal/donna128.h
Line | Count | Source |
1 | | /* |
2 | | * A minimal 128-bit integer type |
3 | | * (C) 2014 Jack Lloyd |
4 | | * |
5 | | * Botan is released under the Simplified BSD License (see license.txt) |
6 | | */ |
7 | | |
8 | | #ifndef BOTAN_DONNA128_H_ |
9 | | #define BOTAN_DONNA128_H_ |
10 | | |
11 | | #include <botan/internal/ct_utils.h> |
12 | | #include <botan/internal/mul128.h> |
13 | | #include <concepts> |
14 | | |
15 | | namespace Botan { |
16 | | |
17 | | class donna128 final { |
18 | | public: |
19 | 0 | constexpr explicit donna128(uint64_t l = 0, uint64_t h = 0) : m_lo(l), m_hi(h) {} |
20 | | |
21 | | template <std::unsigned_integral T> |
22 | 0 | constexpr friend donna128 operator>>(const donna128& x, T shift) { |
23 | 0 | donna128 z = x; |
24 | 0 |
|
25 | 0 | if(shift > 64) { |
26 | 0 | z.m_lo = z.m_hi >> (shift - 64); |
27 | 0 | z.m_hi = 0; |
28 | 0 | } else if(shift == 64) { |
29 | 0 | z.m_lo = z.m_hi; |
30 | 0 | z.m_hi = 0; |
31 | 0 | } else if(shift > 0) { |
32 | 0 | const uint64_t carry = z.m_hi << static_cast<size_t>(64 - shift); |
33 | 0 | z.m_hi >>= shift; |
34 | 0 | z.m_lo >>= shift; |
35 | 0 | z.m_lo |= carry; |
36 | 0 | } |
37 | 0 |
|
38 | 0 | return z; |
39 | 0 | } |
40 | | |
41 | | template <std::unsigned_integral T> |
42 | 0 | constexpr friend donna128 operator<<(const donna128& x, T shift) { |
43 | 0 | donna128 z = x; |
44 | 0 | if(shift > 64) { |
45 | 0 | z.m_hi = z.m_lo << (shift - 64); |
46 | 0 | z.m_lo = 0; |
47 | 0 | } else if(shift == 64) { |
48 | 0 | z.m_hi = z.m_lo; |
49 | 0 | z.m_lo = 0; |
50 | 0 | } else if(shift > 0) { |
51 | 0 | const uint64_t carry = z.m_lo >> static_cast<size_t>(64 - shift); |
52 | 0 | z.m_lo = (z.m_lo << shift); |
53 | 0 | z.m_hi = (z.m_hi << shift) | carry; |
54 | 0 | } |
55 | 0 |
|
56 | 0 | return z; |
57 | 0 | } |
58 | | |
59 | 0 | constexpr friend uint64_t operator&(const donna128& x, uint64_t mask) { return x.m_lo & mask; } |
60 | | |
61 | 0 | constexpr uint64_t operator&=(uint64_t mask) { |
62 | 0 | m_hi = 0; |
63 | 0 | m_lo &= mask; |
64 | 0 | return m_lo; |
65 | 0 | } |
66 | | |
67 | 0 | constexpr donna128& operator+=(const donna128& x) { |
68 | 0 | m_lo += x.m_lo; |
69 | 0 | m_hi += x.m_hi; |
70 | 0 |
|
71 | 0 | const uint64_t carry = CT::Mask<uint64_t>::is_lt(m_lo, x.m_lo).if_set_return(1); |
72 | 0 | m_hi += carry; |
73 | 0 | return *this; |
74 | 0 | } |
75 | | |
76 | 0 | constexpr donna128& operator+=(uint64_t x) { |
77 | 0 | m_lo += x; |
78 | 0 | const uint64_t carry = CT::Mask<uint64_t>::is_lt(m_lo, x).if_set_return(1); |
79 | 0 | m_hi += carry; |
80 | 0 | return *this; |
81 | 0 | } |
82 | | |
83 | 0 | constexpr uint64_t lo() const { return m_lo; } |
84 | | |
85 | 0 | constexpr uint64_t hi() const { return m_hi; } |
86 | | |
87 | 0 | constexpr explicit operator uint64_t() const { return lo(); } |
88 | | |
89 | | private: |
90 | | uint64_t m_lo = 0; |
91 | | uint64_t m_hi = 0; |
92 | | }; |
93 | | |
94 | | template <std::integral T> |
95 | | constexpr inline donna128 operator*(const donna128& x, T y) { |
96 | | BOTAN_ARG_CHECK(x.hi() == 0, "High 64 bits of donna128 set to zero during multiply"); |
97 | | |
98 | | uint64_t lo = 0; |
99 | | uint64_t hi = 0; |
100 | | mul64x64_128(x.lo(), static_cast<uint64_t>(y), &lo, &hi); |
101 | | return donna128(lo, hi); |
102 | | } |
103 | | |
104 | | template <std::integral T> |
105 | | constexpr inline donna128 operator*(T y, const donna128& x) { |
106 | | return x * y; |
107 | | } |
108 | | |
109 | 0 | constexpr inline donna128 operator+(const donna128& x, const donna128& y) { |
110 | 0 | donna128 z = x; |
111 | 0 | z += y; |
112 | 0 | return z; |
113 | 0 | } |
114 | | |
115 | 0 | constexpr inline donna128 operator+(const donna128& x, uint64_t y) { |
116 | 0 | donna128 z = x; |
117 | 0 | z += y; |
118 | 0 | return z; |
119 | 0 | } |
120 | | |
121 | 0 | constexpr inline donna128 operator|(const donna128& x, const donna128& y) { |
122 | 0 | return donna128(x.lo() | y.lo(), x.hi() | y.hi()); |
123 | 0 | } |
124 | | |
125 | 0 | constexpr inline donna128 operator|(const donna128& x, uint64_t y) { |
126 | 0 | return donna128(x.lo() | y, x.hi()); |
127 | 0 | } |
128 | | |
129 | 0 | constexpr inline uint64_t carry_shift(const donna128& a, size_t shift) { |
130 | 0 | return (a >> shift).lo(); |
131 | 0 | } |
132 | | |
133 | 0 | constexpr inline uint64_t combine_lower(const donna128& a, size_t s1, const donna128& b, size_t s2) { |
134 | 0 | donna128 z = (a >> s1) | (b << s2); |
135 | 0 | return z.lo(); |
136 | 0 | } |
137 | | |
138 | | #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) |
139 | 0 | inline uint64_t carry_shift(const uint128_t a, size_t shift) { |
140 | 0 | return static_cast<uint64_t>(a >> shift); |
141 | 0 | } |
142 | | |
143 | 0 | inline uint64_t combine_lower(const uint128_t a, size_t s1, const uint128_t b, size_t s2) { |
144 | 0 | return static_cast<uint64_t>((a >> s1) | (b << s2)); |
145 | 0 | } |
146 | | #endif |
147 | | |
148 | | } // namespace Botan |
149 | | |
150 | | #endif |