aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2019-02-22 12:44:36 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2019-02-22 12:45:56 +0000
commit066c79a8439cbfddb94a4ff6158a443926af22b0 (patch)
tree4c7d0d4bb451527ae0523ed5f7f9441254ad03ec
parent374787a438cae6000dc8fd895d20349aba84a143 (diff)
downloadaports-066c79a8439cbfddb94a4ff6158a443926af22b0.tar.bz2
aports-066c79a8439cbfddb94a4ff6158a443926af22b0.tar.xz
community/rethinkdb: use upstream patch for openssl 1.1 support
patch is from https://github.com/rethinkdb/rethinkdb/commit/3156820e058cd410078a4c39d5a2a85f6b714c07
-rw-r--r--community/rethinkdb/APKBUILD4
-rw-r--r--community/rethinkdb/openssl-1.1-all.patch343
2 files changed, 231 insertions, 116 deletions
diff --git a/community/rethinkdb/APKBUILD b/community/rethinkdb/APKBUILD
index 3f89740d20..1313ca61a1 100644
--- a/community/rethinkdb/APKBUILD
+++ b/community/rethinkdb/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: Daniel Treadwell <daniel@djt.id.au>
pkgname=rethinkdb
pkgver=2.3.6
-pkgrel=8
+pkgrel=9
pkgdesc="Distributed powerful and scalable NoSQL database"
url="https://www.rethinkdb.com"
arch="x86_64 ppc64le s390x"
@@ -85,7 +85,7 @@ doc() {
sha512sums="653177750f7439fa1d61a121e488d578be1eab90f87c7d17ad52b9793d8543f22bbe98f8d501c2ab2d7048c65118096430fe7bde945d87c7a3228905af801af2 rethinkdb-2.3.6.tgz
9ff727feedc7a9f58e7bf8554dc26e32ebca259b2d5d75ff0d064f5aea7a54c9c94fab16b83a3bc4039d4ae6d6d805d7b129ab9d5f762186d0388adeeff6e67c libressl-all.patch
-30a74f731d235aa9d914ad84ac939541c5c7c4e9b9c3a6f5e1511d8c6bd2f94c78ae603ff22d00b246992b205470ffc763faa93f19667f56a3226ef230d8ac35 openssl-1.1-all.patch
+967d53a8729a01fbc67529b906fd3a62543f7f71a0086cce1128b19c90757c08ebc72cc94e8ef6b98d4adfeb33b4d214519217240b49da57da6375ff42e6ba17 openssl-1.1-all.patch
63e9b4c145617a91d00c78c980937c4f4dc010c7bc4a8db8d7ecaad47dbecd0333fcaadbfe0251dee50f44494e802db5322d8cc0096cf614f44fd4069e82f8ac enable-build-ppc64le.patch
04f6e00242ce025ba116e3dae1bf9ccd887901d9d0700faa006b72c4a1c5bd94996a9062db32b11ed0cd6a96af1f11786746ba446d288f6d921f6d93c2158cae enable-build-s390x.patch
c5a7905c116a2bf7af5ce5f8e6536c61e06ee9ac7cbead0358396e0989141890908eab694f4a88f0dcaf9f4ddcefe751dc7a949cbb4c870d87f61e720ef3b45a paxmark-x86_64.patch
diff --git a/community/rethinkdb/openssl-1.1-all.patch b/community/rethinkdb/openssl-1.1-all.patch
index 9cf073819e..5780771f59 100644
--- a/community/rethinkdb/openssl-1.1-all.patch
+++ b/community/rethinkdb/openssl-1.1-all.patch
@@ -1,73 +1,121 @@
-server.cc change my original work.
-s2 exactfloat changes based to upstream changes from https://github.com/google/s2geometry
+From 3156820e058cd410078a4c39d5a2a85f6b714c07 Mon Sep 17 00:00:00 2001
+From: Sam Hughes <sam@samuelhughes.com>
+Date: Mon, 19 Jun 2017 20:27:15 -0700
+Subject: [PATCH] Make BIGNUM functions in geo code avoid removed SSL API's
-diff -ru rethinkdb-2.3.6.orig/src/client_protocol/server.cc rethinkdb-2.3.6/src/client_protocol/server.cc
---- rethinkdb-2.3.6.orig/src/client_protocol/server.cc 1970-01-01 02:00:01.000000000 +0200
-+++ rethinkdb-2.3.6/src/client_protocol/server.cc 2019-01-02 10:25:11.885832550 +0200
-@@ -174,12 +174,9 @@
+- BIGNUM functions now avoid accessing ->d and ->top
+
+- Allocates EVP_MD_CTX on the heap
+
+- Adds the unittest BignumTest
+---
+ src/client_protocol/server.cc | 9 +-
+ .../geo/s2/util/math/exactfloat/exactfloat.cc | 130 +++++++++---------
+ .../geo/s2/util/math/exactfloat/exactfloat.h | 27 ++--
+ src/unittest/bignum_test.cc | 59 ++++++++
+ 4 files changed, 147 insertions(+), 78 deletions(-)
+ create mode 100644 src/unittest/bignum_test.cc
+
+diff --git a/src/client_protocol/server.cc b/src/client_protocol/server.cc
+index 4b9c4299f06..ccce61ca297 100644
+--- a/src/client_protocol/server.cc
++++ b/src/client_protocol/server.cc
+@@ -174,12 +174,13 @@ void http_conn_cache_t::on_ring() {
}
size_t http_conn_cache_t::sha_hasher_t::operator()(const conn_key_t &x) const {
- EVP_MD_CTX c;
- EVP_DigestInit(&c, EVP_sha256());
- EVP_DigestUpdate(&c, x.data(), x.size());
++ EVP_MD_CTX *c = EVP_MD_CTX_create();
++ EVP_DigestInit(c, EVP_sha256());
++ EVP_DigestUpdate(c, x.data(), x.size());
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int digest_size = 0;
- EVP_DigestFinal(&c, digest, &digest_size);
-+ EVP_Digest(x.data(), x.size(), digest, &digest_size, EVP_sha256(), NULL);
++ EVP_DigestFinal(c, digest, &digest_size);
++ EVP_MD_CTX_destroy(c);
rassert(digest_size >= sizeof(size_t));
size_t res = 0;
memcpy(&res, digest, std::min(sizeof(size_t), static_cast<size_t>(digest_size)));
-diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc rethinkdb-2.3.6/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc
---- rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc 1970-01-01 02:00:01.000000000 +0200
-+++ rethinkdb-2.3.6/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc 2019-01-02 11:02:41.502810906 +0200
-@@ -86,6 +86,8 @@
- #endif
+diff --git a/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc b/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc
+index 1f3c5c7a85f..383d040f55c 100644
+--- a/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc
++++ b/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.cc
+@@ -60,7 +60,7 @@ bool bn_is_negative_func(const BIGNUM* bn) {
}
-+#if OPENSSL_VERSION_NUMBER < 0x10100000L
-+
- // Count the number of low-order zero bits in the given BIGNUM (ignoring its
- // sign). Returns 0 if the argument is zero.
- static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
-@@ -104,8 +106,35 @@
- return count;
- }
+ // Set a BIGNUM to the given unsigned 64-bit value.
+-inline static void BN_ext_set_uint64(BIGNUM* bn, uint64 v) {
++void BN_ext_set_uint64(BIGNUM* bn, uint64 v) {
+ #if BN_BITS2 == 64
+ CHECK(BN_set_word(bn, v));
+ #else
+@@ -73,39 +73,38 @@ inline static void BN_ext_set_uint64(BIGNUM* bn, uint64 v) {
-+#else // OPENSSL_VERSION_NUMBER >= 0x10100000L
+ // Return the absolute value of a BIGNUM as a 64-bit unsigned integer.
+ // Requires that BIGNUM fits into 64 bits.
+-inline static uint64 BN_ext_get_uint64(const BIGNUM* bn) {
+- DCHECK_LE(BN_num_bytes(bn), static_cast<int>(sizeof(uint64)));
+-#if BN_BITS2 == 64
+- return BN_get_word(bn);
+-#else
+- COMPILE_ASSERT(BN_BITS2 == 32, at_least_32_bit_openssl_build_needed);
+- if (bn->top == 0) return 0;
+- if (bn->top == 1) return BN_get_word(bn);
+- DCHECK_EQ(bn->top, 2);
+- return (static_cast<uint64>(bn->d[1]) << 32) + bn->d[0];
+-#endif
++uint64 BN_ext_get_uint64(const BIGNUM* bn) {
++ int num_bytes = BN_num_bytes(bn);
++ DCHECK_LE(num_bytes, 8);
+
-+static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
-+ // In OpenSSL >= 1.1, BIGNUM is an opaque type, so d and top
-+ // cannot be accessed. The bytes must be copied out at a ~25%
-+ // performance penalty.
-+ int size = BN_num_bytes(bn);
-+ unsigned char bytes[size];
-+ // "le" indicates little endian.
-+ CHECK_EQ(BN_bn2lebinpad(bn, bytes, size), size);
++ std::unique_ptr<unsigned char[]> buf(new unsigned char[num_bytes]);
++ int res = BN_bn2bin(bn, buf.get());
++ DCHECK_EQ(num_bytes, res);
+
-+ int count = 0;
-+ for (unsigned char c : bytes) {
-+ if (c == 0) {
-+ count += 8;
-+ } else {
-+ for (; (c & 1) == 0; c >>= 1) {
-+ ++count;
-+ }
-+ break;
-+ }
++ uint64_t ret = 0;
++ for (int i = 0; i < res; ++i) {
++ ret = ret * 256;
++ ret += buf[i];
+ }
-+ return count;
-+}
-+
+
-+#endif
-+
- ExactFloat::ExactFloat(double v) {
++ return ret;
+ }
+
+ // Count the number of low-order zero bits in the given BIGNUM (ignoring its
+ // sign). Returns 0 if the argument is zero.
+-static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
+- int count = 0;
+- for (int i = 0; i < bn->top; ++i) {
+- BN_ULONG w = bn->d[i];
+- if (w == 0) {
+- count += 8 * sizeof(BN_ULONG);
+- } else {
+- for (; (w & 1) == 0; w >>= 1) {
+- ++count;
++int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
++ int num_bytes = BN_num_bytes(bn);
++ for (int i = 0; i < num_bytes * 8; ++i) {
++ if (BN_is_bit_set(bn, i)) {
++ return i;
+ }
+- break;
+- }
+ }
+- return count;
++ // They're all zero. What now? Just going to treat this as if BN_num_bytes had been
++ // zero in any case.
++ return 0;
+ }
+
+-ExactFloat::ExactFloat(double v) {
- BN_init(&bn_);
++ExactFloat::ExactFloat(double v) : bn_(make_BN_new()) {
sign_ = signbit(v) ? -1 : 1;
if (std::isnan(v)) {
set_nan();
-@@ -121,18 +150,17 @@
+@@ -121,27 +120,26 @@ ExactFloat::ExactFloat(double v) {
int expl;
double f = frexp(fabs(v), &expl);
uint64 m = static_cast<uint64>(ldexp(f, kDoubleMantissaBits));
@@ -78,8 +126,9 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
}
}
- ExactFloat::ExactFloat(int v) {
+-ExactFloat::ExactFloat(int v) {
- BN_init(&bn_);
++ExactFloat::ExactFloat(int v) : bn_(make_BN_new()) {
sign_ = (v >= 0) ? 1 : -1;
// Note that this works even for INT_MIN because the parameter type for
// BN_set_word() is unsigned.
@@ -88,17 +137,19 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
bn_exp_ = 0;
Canonicalize();
}
-@@ -140,8 +168,7 @@
+
ExactFloat::ExactFloat(const ExactFloat& b)
: sign_(b.sign_),
- bn_exp_(b.bn_exp_) {
+- bn_exp_(b.bn_exp_) {
- BN_init(&bn_);
- BN_copy(&bn_, &b.bn_);
++ bn_exp_(b.bn_exp_),
++ bn_(make_BN_new()) {
+ BN_copy(bn_.get(), b.bn_.get());
}
ExactFloat ExactFloat::SignedZero(int sign) {
-@@ -163,30 +190,30 @@
+@@ -163,30 +161,30 @@ ExactFloat ExactFloat::NaN() {
}
int ExactFloat::prec() const {
@@ -134,7 +185,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
}
double ExactFloat::ToDouble() const {
-@@ -200,13 +227,13 @@
+@@ -200,13 +198,13 @@ double ExactFloat::ToDouble() const {
}
double ExactFloat::ToDoubleHelper() const {
@@ -150,7 +201,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
// We rely on ldexp() to handle overflow and underflow. (It will return a
// signed zero or infinity if the result is too small or too large.)
return sign_ * ldexp(static_cast<double>(d_mantissa), bn_exp_);
-@@ -257,11 +284,11 @@
+@@ -257,11 +255,11 @@ ExactFloat ExactFloat::RoundToPowerOf2(int bit_exp, RoundingMode mode) const {
// Never increment.
} else if (mode == kRoundTiesAwayFromZero) {
// Increment if the highest discarded bit is 1.
@@ -164,7 +215,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
increment = true;
} else {
DCHECK_EQ(mode, kRoundTiesToEven);
-@@ -271,16 +298,16 @@
+@@ -271,16 +269,16 @@ ExactFloat ExactFloat::RoundToPowerOf2(int bit_exp, RoundingMode mode) const {
// 0/10* -> Don't increment (fraction = 1/2, kept part even)
// 1/10* -> Increment (fraction = 1/2, kept part odd)
// ./1.*1.* -> Increment (fraction > 1/2)
@@ -186,7 +237,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
}
r.sign_ = sign_;
r.Canonicalize();
-@@ -387,7 +414,7 @@
+@@ -387,7 +385,7 @@ int ExactFloat::GetDecimalDigits(int max_digits, std::string* digits) const {
int bn_exp10;
if (bn_exp_ >= 0) {
// The easy case: bn = bn_ * (2 ** bn_exp_)), bn_exp10 = 0.
@@ -195,7 +246,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
bn_exp10 = 0;
} else {
// Set bn = bn_ * (5 ** -bn_exp_) and bn_exp10 = bn_exp_. This is
-@@ -397,7 +424,7 @@
+@@ -397,7 +395,7 @@ int ExactFloat::GetDecimalDigits(int max_digits, std::string* digits) const {
CHECK(BN_set_word(bn, 5));
BN_CTX* ctx = BN_CTX_new();
CHECK(BN_exp(bn, bn, power, ctx));
@@ -204,7 +255,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
BN_CTX_free(ctx);
BN_free(power);
bn_exp10 = bn_exp_;
-@@ -453,7 +480,7 @@
+@@ -453,7 +451,7 @@ ExactFloat& ExactFloat::operator=(const ExactFloat& b) {
if (this != &b) {
sign_ = b.sign_;
bn_exp_ = b.bn_exp_;
@@ -213,7 +264,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
}
return *this;
}
-@@ -500,24 +527,24 @@
+@@ -500,24 +498,24 @@ ExactFloat ExactFloat::SignedSum(int a_sign, const ExactFloat* a,
// Shift "a" if necessary so that both values have the same bn_exp_.
ExactFloat r;
if (a->bn_exp_ > b->bn_exp_) {
@@ -244,7 +295,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
} else {
// They were equal, or the magnitude of "a" was larger.
r.sign_ = a_sign;
-@@ -533,16 +560,16 @@
+@@ -533,16 +531,16 @@ void ExactFloat::Canonicalize() {
// Underflow/overflow occurs if exp() is not in [kMinExp, kMaxExp].
// We also convert a zero mantissa to signed zero.
int my_exp = exp();
@@ -266,7 +317,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
bn_exp_ += shift;
}
}
-@@ -575,7 +602,7 @@
+@@ -575,7 +573,7 @@ ExactFloat operator*(const ExactFloat& a, const ExactFloat& b) {
r.sign_ = result_sign;
r.bn_exp_ = a.bn_exp_ + b.bn_exp_;
BN_CTX* ctx = BN_CTX_new();
@@ -275,7 +326,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
BN_CTX_free(ctx);
r.Canonicalize();
return r;
-@@ -594,14 +621,14 @@
+@@ -594,14 +592,14 @@ bool operator==(const ExactFloat& a, const ExactFloat& b) {
// Otherwise, the signs and mantissas must match. Note that non-normal
// values such as infinity have a mantissa of zero.
@@ -293,7 +344,7 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
}
bool ExactFloat::UnsignedLess(const ExactFloat& b) const {
-@@ -692,7 +719,7 @@
+@@ -692,7 +690,7 @@ T ExactFloat::ToInteger(RoundingMode mode) const {
if (!r.is_inf()) {
// If the unsigned value has more than 63 bits it is always clamped.
if (r.exp() < 64) {
@@ -302,75 +353,139 @@ diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exact
if (r.sign_ < 0) value = -value;
return max(kMinValue, min(kMaxValue, value));
}
-diff -ru rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h rethinkdb-2.3.6/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h
---- rethinkdb-2.3.6.orig/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h 1970-01-01 02:00:01.000000000 +0200
-+++ rethinkdb-2.3.6/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h 2019-01-02 10:49:43.488914196 +0200
-@@ -174,7 +174,7 @@
+diff --git a/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h b/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h
+index b91290799c6..2c472778fda 100644
+--- a/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h
++++ b/src/rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h
+@@ -96,8 +96,9 @@
- // The destructor is not virtual for efficiency reasons. Therefore no
- // subclass should declare additional fields that require destruction.
-- inline ~ExactFloat();
-+ inline ~ExactFloat() = default;
+ #include <math.h>
+ #include <limits.h>
+-#include <iostream>
- /////////////////////////////////////////////////////////////////////
- // Constants
-@@ -485,6 +485,38 @@
- friend ExactFloat logb(const ExactFloat& a);
++#include <iostream>
++#include <memory>
+ #include <string>
- protected:
-+ // OpenSSL >= 1.1 does not have BN_init, and does not support stack-
-+ // allocated BIGNUMS. We use BN_init when possible, but BN_new otherwise.
-+ // If the performance penalty is too high, an object pool can be added
-+ // in the future.
-+#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10100000L
-+ // BoringSSL and OpenSSL < 1.1 support stack allocated BIGNUMs and BN_init.
-+ class BigNum {
-+ public:
-+ BigNum() { BN_init(&bn_); }
-+ // Prevent accidental, expensive, copying.
-+ BigNum(const BigNum&) = delete;
-+ BigNum& operator=(const BigNum&) = delete;
-+ ~BigNum() { BN_free(&bn_); }
-+ BIGNUM* get() { return &bn_; }
-+ const BIGNUM* get() const { return &bn_; }
-+ private:
-+ BIGNUM bn_;
-+ };
-+#else
-+ class BigNum {
-+ public:
-+ BigNum() : bn_(BN_new()) {}
-+ BigNum(const BigNum&) = delete;
-+ BigNum& operator=(const BigNum&) = delete;
-+ ~BigNum() { BN_free(bn_); }
-+ BIGNUM* get() { return bn_; }
-+ const BIGNUM* get() const { return bn_; }
-+ private:
-+ BIGNUM* bn_;
-+ };
-+#endif
+ #include <openssl/bn.h>
+@@ -107,6 +108,10 @@
+
+ namespace geo {
+
++struct BIGNUM_deleter {
++ void operator()(BIGNUM *b) { BN_free(b); }
++};
+
- // Non-normal numbers are represented using special exponent values and a
- // mantissa of zero. Do not change these values; methods such as
- // is_normal() make assumptions about their ordering. Non-normal numbers
-@@ -499,7 +531,7 @@
+ class ExactFloat {
+ public:
+ // The following limits are imposed by OpenSSL.
+@@ -499,7 +504,7 @@ class ExactFloat {
// - bn_exp_ is the base-2 exponent applied to bn_.
int32 sign_;
int32 bn_exp_;
- BIGNUM bn_;
-+ BigNum bn_;
++ std::unique_ptr<BIGNUM, BIGNUM_deleter> bn_;
// A standard IEEE "double" has a 53-bit mantissa consisting of a 52-bit
// fraction plus an implicit leading "1" bit.
-@@ -559,11 +591,6 @@
+@@ -555,16 +560,18 @@ class ExactFloat {
+ static ExactFloat Unimplemented();
+ };
+
++inline std::unique_ptr<BIGNUM, BIGNUM_deleter> make_BN_new() {
++ std::unique_ptr<BIGNUM, BIGNUM_deleter> ret(BN_new(), BIGNUM_deleter{});
++ guarantee(ret.get() != nullptr);
++ return ret;
++}
++
+ /////////////////////////////////////////////////////////////////////////
// Implementation details follow:
- inline ExactFloat::ExactFloat() : sign_(1), bn_exp_(kExpZero) {
+-inline ExactFloat::ExactFloat() : sign_(1), bn_exp_(kExpZero) {
- BN_init(&bn_);
-}
--
++inline ExactFloat::ExactFloat() : sign_(1), bn_exp_(kExpZero), bn_(make_BN_new()) {}
+
-inline ExactFloat::~ExactFloat() {
- BN_free(&bn_);
- }
+-}
++inline ExactFloat::~ExactFloat() {}
inline bool ExactFloat::is_zero() const { return bn_exp_ == kExpZero; }
+ inline bool ExactFloat::is_inf() const { return bn_exp_ == kExpInfinity; }
+@@ -601,6 +608,10 @@ inline ExactFloat ExactFloat::CopyWithSign(int sign) const {
+ return r;
+ }
+
++void BN_ext_set_uint64(BIGNUM *bn, uint64 v);
++uint64 BN_ext_get_uint64(const BIGNUM *bn);
++int BN_ext_count_low_zero_bits(const BIGNUM *bn);
++
+ } // namespace geo
+
+ #endif // UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_
+diff --git a/src/unittest/bignum_test.cc b/src/unittest/bignum_test.cc
+new file mode 100644
+index 00000000000..2aba6456103
+--- /dev/null
++++ b/src/unittest/bignum_test.cc
+@@ -0,0 +1,59 @@
++#include "unittest/gtest.hpp"
++
++#include "rdb_protocol/geo/s2/util/math/exactfloat/exactfloat.h"
++
++namespace unittest {
++
++TEST(BignumTest, TestGetUint64) {
++ std::unique_ptr<BIGNUM, geo::BIGNUM_deleter> bn = geo::make_BN_new();
++
++ uint64_t x = geo::BN_ext_get_uint64(bn.get());
++ ASSERT_EQ(0, x);
++
++ uint64_t values[4] = { 1, (1ull << 32) - 1, (1ull << 32), uint64_t(-1) };
++ for (int i = 0; i < 4; ++i) {
++ geo::BN_ext_set_uint64(bn.get(), values[i]);
++ ASSERT_EQ(values[i], geo::BN_ext_get_uint64(bn.get()));
++ }
++}
++
++TEST(BignumTest, TestCountLowZeroBits) {
++ std::unique_ptr<BIGNUM, geo::BIGNUM_deleter> bn = geo::make_BN_new();
++ int n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(0, n);
++
++ geo::BN_ext_set_uint64(bn.get(), 1);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(0, n);
++
++ geo::BN_ext_set_uint64(bn.get(), 2);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(1, n);
++
++ geo::BN_ext_set_uint64(bn.get(), 128);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(7, n);
++
++ geo::BN_ext_set_uint64(bn.get(), 256);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(8, n);
++
++ geo::BN_ext_set_uint64(bn.get(), 257);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(0, n);
++
++ for (int i = 0; i < 64; i++) {
++ geo::BN_ext_set_uint64(bn.get(), (1ull << i));
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(i, n);
++ }
++
++ geo::BN_ext_set_uint64(bn.get(), (1ull << 63));
++ BN_CTX *ctx = BN_CTX_new();
++ BN_mul(bn.get(), bn.get(), bn.get(), ctx);
++ BN_CTX_free(ctx);
++ n = geo::BN_ext_count_low_zero_bits(bn.get());
++ ASSERT_EQ(126, n);
++}
++
++} // namespace unittest