xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
include
xrpl
protocol
detail
b58_utils.h
1
#pragma once
2
3
#include <xrpl/beast/utility/instrumentation.h>
4
#include <xrpl/protocol/detail/token_errors.h>
5
6
#include <boost/outcome.hpp>
7
#include <boost/outcome/result.hpp>
8
9
#include <
array
>
10
#include <
cstddef
>
11
#include <
cstdint
>
12
#include <
span
>
13
#include <
system_error
>
14
#include <
tuple
>
15
16
namespace
xrpl
{
17
18
template
<
class
T>
19
using
Result
= boost::outcome_v2::result<T, std::error_code>;
20
21
#ifndef _MSC_VER
22
23
namespace
b58_fast::detail {
24
25
// This optimizes to what hand written asm would do (single divide)
26
[[nodiscard]]
inline
std::tuple<std::uint64_t, std::uint64_t>
27
divRem(
std::uint64_t
a,
std::uint64_t
b)
28
{
29
return
{a / b, a % b};
30
}
31
32
// This optimizes to what hand written asm would do (single multiply)
33
[[nodiscard]]
inline
std::tuple<std::uint64_t, std::uint64_t>
34
carryingMul(
std::uint64_t
a,
std::uint64_t
b,
std::uint64_t
carry)
35
{
36
unsigned
__int128
const
x = a;
37
unsigned
__int128
const
y = b;
38
unsigned
__int128
const
c = (x * y) + carry;
39
return
{c & 0xffff'ffff'ffff'ffff, c >> 64};
40
}
41
42
[[nodiscard]]
inline
std::tuple<std::uint64_t, std::uint64_t>
43
carryingAdd(
std::uint64_t
a,
std::uint64_t
b)
44
{
45
unsigned
__int128
const
x = a;
46
unsigned
__int128
const
y = b;
47
unsigned
__int128
const
c = x + y;
48
return
{c & 0xffff'ffff'ffff'ffff, c >> 64};
49
}
50
51
// Add a u64 to a "big uint" value inplace.
52
// The bigint value is stored with the smallest coefficients first
53
// (i.e a[0] is the 2^0 coefficient, a[n] is the 2^(64*n) coefficient)
54
// panics if overflows (this is a specialized adder for b58 decoding.
55
// it should never overflow).
56
[[nodiscard]]
inline
TokenCodecErrc
57
inplaceBigintAdd(
std::span<std::uint64_t>
a,
std::uint64_t
b)
58
{
59
if
(a.size() <= 1)
60
{
61
return
TokenCodecErrc::InputTooSmall
;
62
}
63
64
std::uint64_t
carry = 0;
65
std::tie
(a[0], carry) = carryingAdd(a[0], b);
66
67
for
(
auto
& v : a.subspan(1))
68
{
69
if
(carry == 0u)
70
{
71
return
TokenCodecErrc::Success
;
72
}
73
std::tie
(v, carry) = carryingAdd(v, 1);
74
}
75
if
(carry != 0u)
76
{
77
return
TokenCodecErrc::OverflowAdd
;
78
}
79
return
TokenCodecErrc::Success
;
80
}
81
82
[[nodiscard]]
inline
TokenCodecErrc
83
inplaceBigintMul(
std::span<std::uint64_t>
a,
std::uint64_t
b)
84
{
85
if
(a.empty())
86
{
87
return
TokenCodecErrc::InputTooSmall
;
88
}
89
90
auto
const
lastIndex = a.size() - 1;
91
if
(a[lastIndex] != 0)
92
{
93
return
TokenCodecErrc::InputTooLarge
;
94
}
95
96
std::uint64_t
carry = 0;
97
for
(
auto
& coeff : a.subspan(0, lastIndex))
98
{
99
std::tie
(coeff, carry) = carryingMul(coeff, b, carry);
100
}
101
a[lastIndex] = carry;
102
return
TokenCodecErrc::Success
;
103
}
104
105
// divide a "big uint" value inplace and return the mod
106
// numerator is stored so smallest coefficients come first
107
[[nodiscard]]
inline
std::uint64_t
108
inplaceBigintDivRem(
std::span<uint64_t>
numerator,
std::uint64_t
divisor)
109
{
110
if
(numerator.
empty
())
111
{
112
// should never happen, but if it does then it seems natural to define
113
// the a null set of numbers to be zero, so the remainder is also zero.
114
// LCOV_EXCL_START
115
UNREACHABLE(
116
"xrpl::b58_fast::detail::inplaceBigintDivRem : empty "
117
"numerator"
);
118
return
0;
119
// LCOV_EXCL_STOP
120
}
121
122
auto
toU128 = [](
std::uint64_t
high,
std::uint64_t
low) ->
unsigned
__int128 {
123
unsigned
__int128
const
high128 = high;
124
unsigned
__int128
const
low128 = low;
125
return
((high128 << 64) | low128);
126
};
127
auto
divRe64 = [](
unsigned
__int128 num,
128
std::uint64_t
denom) ->
std::tuple<std::uint64_t, std::uint64_t>
{
129
unsigned
__int128
const
denom128 = denom;
130
unsigned
__int128
const
d = num / denom128;
131
unsigned
__int128
const
r = num - (denom128 * d);
132
XRPL_ASSERT(
133
d >> 64 == 0,
134
"xrpl::b58_fast::detail::inplaceBigintDivRem::divRe64 : "
135
"valid division result"
);
136
XRPL_ASSERT(
137
r >> 64 == 0,
138
"xrpl::b58_fast::detail::inplaceBigintDivRem::divRe64 : "
139
"valid remainder"
);
140
return
{
static_cast<
std::uint64_t
>
(d),
static_cast<
std::uint64_t
>
(r)};
141
};
142
143
std::uint64_t
prevRem = 0;
144
int
const
lastIndex = numerator.
size
() - 1;
145
std::tie
(numerator[lastIndex], prevRem) = divRem(numerator[lastIndex], divisor);
146
for
(
int
i = lastIndex - 1; i >= 0; --i)
147
{
148
unsigned
__int128
const
curNum = toU128(prevRem, numerator[i]);
149
std::tie
(numerator[i], prevRem) = divRe64(curNum, divisor);
150
}
151
return
prevRem;
152
}
153
154
// convert from base 58^10 to base 58
155
// put largest coeffs first
156
// the `_be` suffix stands for "big endian"
157
[[nodiscard]]
inline
std::array<std::uint8_t, 10>
158
b5810ToB58Be(
std::uint64_t
input)
159
{
160
[[maybe_unused]]
static
constexpr
std::uint64_t
kB5810 = 430804206899405824;
// 58^10;
161
XRPL_ASSERT(input < kB5810,
"xrpl::b58_fast::detail::b5810ToB58Be : valid input"
);
162
static
constexpr
std::size_t
kResultSize = 10;
163
std::array<std::uint8_t, kResultSize>
result{};
164
int
i = 0;
165
while
(input > 0)
166
{
167
std::uint64_t
rem = 0;
168
std::tie
(input, rem) = divRem(input, 58);
169
result[kResultSize - 1 - i] = rem;
170
i += 1;
171
}
172
173
return
result;
174
}
175
}
// namespace b58_fast::detail
176
177
#endif
178
179
}
// namespace xrpl
array
cstddef
cstdint
std::span::empty
T empty(T... args)
std::uint64_t
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::Result
boost::outcome_v2::result< T, std::error_code > Result
Definition
b58_utils.h:19
xrpl::TokenCodecErrc
TokenCodecErrc
Definition
token_errors.h:8
xrpl::TokenCodecErrc::InputTooSmall
@ InputTooSmall
Definition
token_errors.h:11
xrpl::TokenCodecErrc::InputTooLarge
@ InputTooLarge
Definition
token_errors.h:10
xrpl::TokenCodecErrc::Success
@ Success
Definition
token_errors.h:9
xrpl::TokenCodecErrc::OverflowAdd
@ OverflowAdd
Definition
token_errors.h:17
std::span::size
T size(T... args)
std::size_t
span
system_error
std::tie
T tie(T... args)
tuple
Generated by
1.17.0