-
-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
big number implementation, for future use in permissions bitfields (#…
- Loading branch information
Showing
6 changed files
with
222 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/************************************************************************************ | ||
* | ||
* D++, A Lightweight C++ library for Discord | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright 2021 Craig Edwards and D++ contributors | ||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
************************************************************************************/ | ||
|
||
#pragma once | ||
#include <dpp/export.h> | ||
#include <dpp/snowflake.h> | ||
#include <memory> | ||
|
||
namespace dpp { | ||
|
||
/** | ||
* @brief This contains the OpenSSL structs. It is not public, | ||
* so that the public interface doesn't depend on OpenSSL directly. | ||
*/ | ||
struct openssl_bignum; | ||
|
||
/** | ||
* @brief An arbitrary length integer number. | ||
* Officially, the Discord documentation says that permission values can be any arbitrary | ||
* number of digits. At time of writing there are only 50 bits of permissions, but this is | ||
* set to grow larger and potentially past 64 bits. They will continue to send this data | ||
* as a huge single integer at that point, because this is obviously sensible. /s | ||
* | ||
* @note dpp::bignumber uses OpenSSL BN_* under the hood, as we include openssl anyway | ||
* for HTTPS. | ||
*/ | ||
class DPP_EXPORT bignumber { | ||
/** | ||
* @brief Internal opaque struct to contain OpenSSL things | ||
*/ | ||
std::shared_ptr<openssl_bignum> ssl_bn{nullptr}; | ||
public: | ||
/** | ||
* @brief Construct a new bignumber object | ||
*/ | ||
bignumber() = default; | ||
|
||
/** | ||
* @brief Parse a std::string of an arbitrary length number into | ||
* a bignumber. | ||
* @param number_string string representation of a number. The | ||
* number must be an integer, and can be positive or negative. | ||
* @note Prefixing number_string with 0x will parse it as hexadecimal. | ||
* This is not case sensitive. | ||
*/ | ||
bignumber(const std::string& number_string); | ||
|
||
/** | ||
* @brief Build a bignumber from a vector of 64 bit values. | ||
* The values are accepted in "reverse order", so the first vector | ||
* entry at index 0 is the leftmost 64 bits of the bignum. | ||
* The vector can be any arbitrary length. | ||
* @param bits Vector of 64 bit values which represent the number | ||
*/ | ||
bignumber(std::vector<uint64_t> bits); | ||
|
||
/** | ||
* @brief Default destructor | ||
*/ | ||
~bignumber() = default; | ||
|
||
/** | ||
* @brief Get the string representation of the bignumber. | ||
* @param hex If false (the default) the number is returned in | ||
* decimal, else if this parameter is true, it will be returned | ||
* as hex (without leading '0x') | ||
* @return String representation of bignumber | ||
*/ | ||
[[nodiscard]] std::string get_number(bool hex = false) const; | ||
|
||
/** | ||
* @brief Get the array of 64 bit values that represents the | ||
* bignumber. This is what we should use to store bignumbers | ||
* in memory, not this bignumber class itself, as the bignumber | ||
* class instantiates OpenSSL structs and takes significantly | ||
* more ram than just a vector. | ||
* @return Vector of 64 bit values representing the bignumber | ||
*/ | ||
[[nodiscard]] std::vector<uint64_t> get_binary() const; | ||
}; | ||
|
||
} // namespace dpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/************************************************************************************ | ||
* | ||
* D++, A Lightweight C++ library for Discord | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright 2021 Craig Edwards and D++ contributors | ||
* (https://github.com/brainboxdotcc/DPP/graphs/contributors) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
************************************************************************************/ | ||
|
||
#include <dpp/bignum.h> | ||
#include <dpp/stringops.h> | ||
#include <openssl/bn.h> | ||
#include <cmath> | ||
|
||
namespace dpp { | ||
|
||
struct openssl_bignum { | ||
/** | ||
* @brief OpenSSL BIGNUM pointer | ||
*/ | ||
BIGNUM* bn{nullptr}; | ||
|
||
/** | ||
* @brief Construct BIGNUM using RAII | ||
*/ | ||
openssl_bignum() : bn(BN_new()) { | ||
} | ||
|
||
/** | ||
* @brief Destruct BIGNUM using RAII | ||
*/ | ||
~openssl_bignum() { | ||
BN_free(bn); | ||
} | ||
}; | ||
|
||
bignumber::bignumber(const std::string& number_string) : ssl_bn(std::make_shared<openssl_bignum>()) { | ||
if (dpp::lowercase(number_string.substr(0, 2)) == "0x") { | ||
BN_hex2bn(&ssl_bn->bn, number_string.substr(2, number_string.length() - 2).c_str()); | ||
} else { | ||
BN_dec2bn(&ssl_bn->bn, number_string.c_str()); | ||
} | ||
} | ||
|
||
/** | ||
* Flip (reverse) bytes in a uint64_t | ||
* @param bytes 64 bit value | ||
* @return flipped 64 bit value | ||
*/ | ||
inline uint64_t flip_bytes(uint64_t bytes) { | ||
return ((((bytes) & 0xff00000000000000ull) >> 56) | ||
| (((bytes) & 0x00ff000000000000ull) >> 40) | ||
| (((bytes) & 0x0000ff0000000000ull) >> 24) | ||
| (((bytes) & 0x000000ff00000000ull) >> 8) | ||
| (((bytes) & 0x00000000ff000000ull) << 8) | ||
| (((bytes) & 0x0000000000ff0000ull) << 24) | ||
| (((bytes) & 0x000000000000ff00ull) << 40) | ||
| (((bytes) & 0x00000000000000ffull) << 56)); | ||
} | ||
|
||
bignumber::bignumber(std::vector<uint64_t> bits): ssl_bn(std::make_shared<openssl_bignum>()) { | ||
std::reverse(bits.begin(), bits.end()); | ||
for (auto& chunk : bits) { | ||
chunk = flip_bytes(chunk); | ||
} | ||
BN_bin2bn(reinterpret_cast<unsigned char*>(bits.data()), bits.size() * sizeof(uint64_t), ssl_bn->bn); | ||
} | ||
|
||
std::string bignumber::get_number(bool hex) const { | ||
char* number_str = hex ? BN_bn2hex(ssl_bn->bn) : BN_bn2dec(ssl_bn->bn); | ||
std::string returned{number_str}; | ||
OPENSSL_free(number_str); | ||
return returned; | ||
} | ||
|
||
std::vector<uint64_t> bignumber::get_binary() const { | ||
std::size_t size = BN_num_bytes(ssl_bn->bn); | ||
auto size_64_bit = static_cast<std::size_t>(ceil(static_cast<double>(size) / sizeof(uint64_t))); | ||
std::vector<uint64_t> returned; | ||
returned.resize(size_64_bit); | ||
BN_bn2binpad(ssl_bn->bn, reinterpret_cast<unsigned char*>(returned.data()), returned.size() * sizeof(uint64_t)); | ||
std::reverse(returned.begin(), returned.end()); | ||
for (auto& chunk : returned) { | ||
chunk = flip_bytes(chunk); | ||
} | ||
return returned; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters