summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShreyas Kalyan <shreyas.kalyan@mongodb.com>2023-01-26 13:14:48 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-01-31 02:24:42 +0000
commitcdbfa41dcabb3d52ebf093f13d2b1bacd2af1b8a (patch)
treecb289d1d1d795b8dd0cc6cd4e74e20964a264352
parent8aca0afe03fd7f9c3041463a470c7758e3c2a73e (diff)
downloadmongo-cdbfa41dcabb3d52ebf093f13d2b1bacd2af1b8a.tar.gz
SERVER-71325 update libmongocrypt with changes from MONGOCRYPT-509
-rw-r--r--src/third_party/SConscript2
-rw-r--r--src/third_party/libmongocrypt/SConscript4
-rw-r--r--src/third_party/libmongocrypt/dist/src/csfle-markup.cpp1
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-dec128.h684
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-dec128.test.cpp72
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev-private.h37
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev.c250
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-optional-private.h20
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-edge-generation-private.h85
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-edge-generation.c108
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-encoding-private.h33
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-encoding.c302
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-mincover-generator.template.h236
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-mincover-private.h19
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-range-mincover.c115
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-rangeopts.c14
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-reader.c3
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-writer-private.h92
-rw-r--r--src/third_party/libmongocrypt/dist/src/mc-writer.c177
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/check.hpp89
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/endian.h42
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/int128.h23
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/int128.test.cpp131
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/macros.h7
-rw-r--r--src/third_party/libmongocrypt/dist/src/mlib/str.h48
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt-buffer-private.h1
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt-ctx-encrypt.c18
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt-key-broker.c2
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt-marking.c44
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt-private.h13
-rw-r--r--src/third_party/libmongocrypt/dist/src/mongocrypt.c4
-rwxr-xr-xsrc/third_party/libmongocrypt/import.sh2
32 files changed, 2412 insertions, 266 deletions
diff --git a/src/third_party/SConscript b/src/third_party/SConscript
index 923fb22c1b9..685917b4c2b 100644
--- a/src/third_party/SConscript
+++ b/src/third_party/SConscript
@@ -164,7 +164,7 @@ if not use_system_version_of_library('asio'):
if not use_system_version_of_library('intel_decimal128'):
thirdPartyEnvironmentModifications['intel_decimal128'] = {
- 'CPPPATH': ['#/src/third_party/IntelRDFPMathLib20U1/LIBRARY'],
+ 'CPPPATH': ['#/src/third_party/IntelRDFPMathLib20U1/LIBRARY/src'],
}
if not use_system_version_of_library('icu'):
diff --git a/src/third_party/libmongocrypt/SConscript b/src/third_party/libmongocrypt/SConscript
index 84b707889e1..a3cb1327773 100644
--- a/src/third_party/libmongocrypt/SConscript
+++ b/src/third_party/libmongocrypt/SConscript
@@ -12,6 +12,8 @@ env['CXXFLAGS_WERROR'] = []
env.InjectThirdParty(libraries=['libbson'])
+env.InjectThirdParty(libraries=['intel_decimal128'])
+
env.Append(CPPDEFINES=[
'KMS_MSG_STATIC',
'MONGOCRYPT_STATIC_DEFINE',
@@ -126,6 +128,7 @@ env.Library(
'dist/src/mc-rangeopts.c',
'dist/src/mc-reader.c',
'dist/src/mc-tokens.c',
+ 'dist/src/mc-writer.c',
'dist/src/mongocrypt-binary.c',
'dist/src/mongocrypt-buffer.c',
'dist/src/mongocrypt-cache-collinfo.c',
@@ -153,6 +156,7 @@ env.Library(
'dist/src/mongocrypt.c',
] + additional_sources,
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/third_party/shim_intel_decimal128',
'$BUILD_DIR/third_party/shim_libbson',
],
LIBDEPS_TAGS=[
diff --git a/src/third_party/libmongocrypt/dist/src/csfle-markup.cpp b/src/third_party/libmongocrypt/dist/src/csfle-markup.cpp
index 21437826942..10f67c9e87c 100644
--- a/src/third_party/libmongocrypt/dist/src/csfle-markup.cpp
+++ b/src/third_party/libmongocrypt/dist/src/csfle-markup.cpp
@@ -12,6 +12,7 @@ extern "C" {
#include <iostream>
#include <fstream>
#include <string>
+#include <cstdint>
#include <mongo_crypt-v1.h>
diff --git a/src/third_party/libmongocrypt/dist/src/mc-dec128.h b/src/third_party/libmongocrypt/dist/src/mc-dec128.h
new file mode 100644
index 00000000000..c609b57b0f7
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mc-dec128.h
@@ -0,0 +1,684 @@
+#ifndef MC_DEC128_H_INCLUDED
+#define MC_DEC128_H_INCLUDED
+
+#include <bson/bson.h>
+
+#include <mlib/macros.h>
+#include <mlib/int128.h>
+#include <mlib/endian.h>
+
+// Include the header that declares the DFP functions, which may be macros that
+// expand to renamed symbols:
+#include <bid_conf.h>
+
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+
+MLIB_C_LINKAGE_BEGIN
+
+/// Rounding controls for Decimal128 operations
+typedef enum mc_dec128_rounding_mode {
+ MC_DEC128_ROUND_NEAREST_EVEN = 0,
+ MC_DEC128_ROUND_DOWNWARD = 1,
+ MC_DEC128_ROUND_UPWARD = 2,
+ MC_DEC128_ROUND_TOWARD_ZERO = 3,
+ MC_DEC128_ROUND_NEAREST_AWAY = 4,
+ MC_DEC128_ROUND_DEFAULT = MC_DEC128_ROUND_NEAREST_EVEN,
+} mc_dec128_rounding_mode;
+
+typedef struct mc_dec128_flagset {
+ int bits;
+} mc_dec128_flagset;
+
+// This alignment conditional is the same conditions used in Intel's DFP
+// library, ensuring we match the ABI of the library without pulling the header
+#if defined _MSC_VER
+#if defined _M_IX86 && !defined __INTEL_COMPILER
+#define _mcDec128Align(n)
+#else
+#define _mcDec128Align(n) __declspec(align (n))
+#endif
+#else
+#if !defined HPUX_OS
+#define _mcDec128Align(n) __attribute__ ((aligned (n)))
+#else
+#define _mcDec128Align(n)
+#endif
+#endif
+
+typedef union _mcDec128Align (16)
+{
+ uint64_t _words[2];
+#if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && \
+ !defined(__APPLE__) && !defined(__clang__)
+ // If supported by the compiler, emit a field that can be used to visualize
+ // the value in a debugger.
+ float value_ __attribute__ ((mode (TD)));
+#endif
+}
+mc_dec128;
+
+#undef _mcDec128Align
+
+/// Expands to a dec128 constant value.
+#ifdef __cplusplus
+#define MC_DEC128_C(N) \
+ mc_dec128 _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
+#else
+#define MC_DEC128_C(N) \
+ _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
+#endif
+
+#define MC_DEC128(N) MLIB_INIT (mc_dec128) MC_DEC128_C (N)
+
+#define _mcDec128Combination(Bits) ((uint64_t) (Bits) << (47))
+#define _mcDec128ZeroExpCombo _mcDec128Combination (1 << 7 | 1 << 13 | 1 << 14)
+#define _mcDec128Const(N, Negate) \
+ _mcDec128ConstFromParts ( \
+ N, (_mcDec128ZeroExpCombo | ((uint64_t) (Negate) << 63)))
+#define _mcDec128ConstFromParts(CoeffLow, HighWord) \
+ { \
+ { \
+ MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (CoeffLow) \
+ : (uint64_t) (HighWord), \
+ MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (HighWord) \
+ : (uint64_t) (CoeffLow), \
+ }, \
+ }
+
+static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C (0);
+static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C (1);
+static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C (-1);
+
+/// The greatest-magnitude finite negative value representable in a Decimal128
+#define MC_DEC128_LARGEST_NEGATIVE \
+ mc_dec128_from_string ("-9999999999999999999999999999999999E6111")
+/// The least-magnitude non-zero negative value representable in a Decimal128
+#define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string ("-1E-6176")
+/// The greatest-magnitude finite positive value representable in a Decimal128
+#define MC_DEC128_LARGEST_POSITIVE \
+ mc_dec128_from_string ("9999999999999999999999999999999999E6111")
+/// The least-magnitude non-zero positive value representable in a Decimal128
+#define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string ("1E-6176")
+/// The normalized zero of Decimal128
+#define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C (0)
+/// A zero of Decimal128 with the least exponent
+#define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string ("0E-6176")
+#define _mcDec128InfCombo \
+ _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12)
+#define _mcDec128QuietNaNCombo \
+ _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11)
+
+/// Positive infinity of Decimal128
+#define MC_DEC128_POSITIVE_INFINITY \
+ _mcDec128ConstFromParts (0, _mcDec128InfCombo)
+/// Negative infinity of Decimal128
+#define MC_DEC128_NEGATIVE_INFINITY \
+ _mcDec128ConstFromParts (0, _mcDec128InfCombo | 1ull << 63)
+/// Positve quiet NaN of Decimal128
+#define MC_DEC128_POSITIVE_NAN \
+ _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo)
+/// Negative quiet NaN of Decimal128
+#define MC_DEC128_NEGATIVE_NAN \
+ _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo | 1ull << 63)
+
+
+/**
+ * @brief Convert a double-precision binary floating point value into the
+ * nearest Decimal128 value
+ *
+ * @param d The number to conver
+ * @param rnd The rounding mode in case the value is not exactly representable
+ * @param flags Out param for exception/error flags (Optional)
+ */
+static inline mc_dec128
+mc_dec128_from_double_ex (double d,
+ mc_dec128_rounding_mode rnd,
+ mc_dec128_flagset *flags)
+{
+ extern mc_dec128 binary64_to_bid128 (
+ double d, mc_dec128_rounding_mode, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ return binary64_to_bid128 (d, rnd, flags ? flags : &zero_flags);
+}
+
+/**
+ * @brief Convert a double-precision binary floating point value into the
+ * nearest Decimal128 value
+ */
+static inline mc_dec128
+mc_dec128_from_double (double d)
+{
+ return mc_dec128_from_double_ex (d, MC_DEC128_ROUND_DEFAULT, NULL);
+}
+
+/**
+ * @brief Convert a string representation of a number into the nearest
+ * Decimal128 value
+ *
+ * @param s The string to parse. MUST be null-terminated
+ * @param rnd The rounding mode to use if the result is not representable
+ * @param flags Out param for exception/error flags (Optional)
+ */
+static inline mc_dec128
+mc_dec128_from_string_ex (const char *s,
+ mc_dec128_rounding_mode rnd,
+ mc_dec128_flagset *flags)
+{
+ extern mc_dec128 bid128_from_string (
+ const char *, mc_dec128_rounding_mode, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ return bid128_from_string (s, rnd, flags ? flags : &zero_flags);
+}
+
+/**
+ * @brief Convert a string representation of a number into the nearest
+ * Decimal128 value
+ */
+static inline mc_dec128
+mc_dec128_from_string (const char *s)
+{
+ return mc_dec128_from_string_ex (s, MC_DEC128_ROUND_DEFAULT, NULL);
+}
+
+/**
+ * @brief A type capable of holding a string rendering of a Decimal128 in
+ * engineering notation.
+ */
+typedef struct mc_dec128_string {
+ /// The character array of the rendered value. Null-terminated
+ char str[48];
+} mc_dec128_string;
+
+/**
+ * @brief Render a Decimal128 value as a string (in engineering notation)
+ *
+ * @param d The number to represent
+ * @param flags Output parameter for exception/error flags (optional)
+ */
+static inline mc_dec128_string
+mc_dec128_to_string_ex (mc_dec128 d, mc_dec128_flagset *flags)
+{
+ extern void bid128_to_string (char *, mc_dec128 d, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ mc_dec128_string out = {{0}};
+ bid128_to_string (out.str, d, flags ? flags : &zero_flags);
+ return out;
+}
+
+/**
+ * @brief Render a Decimal128 value as a string (in engineering notation)
+ */
+static inline mc_dec128_string
+mc_dec128_to_string (mc_dec128 d)
+{
+ return mc_dec128_to_string_ex (d, NULL);
+}
+
+/// Compare two dec128 numbers
+#define DECL_IDF_COMPARE_1(Oper) \
+ static inline bool mc_dec128_##Oper##_ex ( \
+ mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) \
+ { \
+ extern int bid128_quiet_##Oper ( \
+ mc_dec128 left, mc_dec128 right, mc_dec128_flagset *); \
+ mc_dec128_flagset zero_flags = {0}; \
+ return 0 != \
+ bid128_quiet_##Oper (left, right, flags ? flags : &zero_flags); \
+ } \
+ \
+ static inline bool mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
+ { \
+ return mc_dec128_##Oper##_ex (left, right, NULL); \
+ }
+
+#define DECL_IDF_COMPARE(Op) \
+ DECL_IDF_COMPARE_1 (Op) \
+ DECL_IDF_COMPARE_1 (not_##Op)
+
+DECL_IDF_COMPARE (equal)
+DECL_IDF_COMPARE (greater)
+DECL_IDF_COMPARE (greater_equal)
+DECL_IDF_COMPARE (less)
+DECL_IDF_COMPARE (less_equal)
+
+#undef DECL_IDF_COMPARE
+#undef DECL_IDF_COMPARE_1
+
+/// Test properties of Decimal128 numbers
+#define DECL_PREDICATE(Name, BIDName) \
+ static inline bool mc_dec128_##Name (mc_dec128 d) \
+ { \
+ extern int bid128_##BIDName (mc_dec128 d); \
+ return 0 != bid128_##BIDName (d); \
+ }
+
+DECL_PREDICATE (is_zero, isZero)
+DECL_PREDICATE (is_negative, isSigned)
+DECL_PREDICATE (is_inf, isInf)
+DECL_PREDICATE (is_finite, isFinite)
+DECL_PREDICATE (is_nan, isNaN)
+
+#undef DECL_PREDICATE
+
+/// Binary arithmetic operations on two Decimal128 numbers
+#define DECL_IDF_BINOP_WRAPPER(Oper) \
+ static inline mc_dec128 mc_dec128_##Oper##_ex ( \
+ mc_dec128 left, \
+ mc_dec128 right, \
+ mc_dec128_rounding_mode mode, \
+ mc_dec128_flagset *flags) \
+ { \
+ extern mc_dec128 bid128_##Oper (mc_dec128 left, \
+ mc_dec128 right, \
+ mc_dec128_rounding_mode rounding, \
+ mc_dec128_flagset *flags); \
+ mc_dec128_flagset zero_flags = {0}; \
+ return bid128_##Oper (left, right, mode, flags ? flags : &zero_flags); \
+ } \
+ \
+ static inline mc_dec128 mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
+ { \
+ return mc_dec128_##Oper##_ex ( \
+ left, right, MC_DEC128_ROUND_DEFAULT, NULL); \
+ }
+
+DECL_IDF_BINOP_WRAPPER (add)
+DECL_IDF_BINOP_WRAPPER (mul)
+DECL_IDF_BINOP_WRAPPER (div)
+DECL_IDF_BINOP_WRAPPER (sub)
+DECL_IDF_BINOP_WRAPPER (pow)
+
+#undef DECL_IDF_BINOP_WRAPPER
+
+/// Unary arithmetic operations on two Decimal128 numbers
+#define DECL_IDF_UNOP_WRAPPER(Oper) \
+ static inline mc_dec128 mc_dec128_##Oper##_ex (mc_dec128 operand, \
+ mc_dec128_flagset *flags) \
+ { \
+ extern mc_dec128 bid128_##Oper ( \
+ mc_dec128 v, mc_dec128_rounding_mode, mc_dec128_flagset *); \
+ mc_dec128_flagset zero_flags = {0}; \
+ return bid128_##Oper ( \
+ operand, MC_DEC128_ROUND_DEFAULT, flags ? flags : &zero_flags); \
+ } \
+ \
+ static inline mc_dec128 mc_dec128_##Oper (mc_dec128 operand) \
+ { \
+ return mc_dec128_##Oper##_ex (operand, NULL); \
+ }
+
+DECL_IDF_UNOP_WRAPPER (round_integral_zero)
+DECL_IDF_UNOP_WRAPPER (round_integral_positive)
+DECL_IDF_UNOP_WRAPPER (round_integral_negative)
+DECL_IDF_UNOP_WRAPPER (round_integral_exact)
+DECL_IDF_UNOP_WRAPPER (log2)
+DECL_IDF_UNOP_WRAPPER (log10)
+DECL_IDF_UNOP_WRAPPER (negate)
+DECL_IDF_UNOP_WRAPPER (abs)
+#undef DECL_IDF_UNOP_WRAPPER
+
+/**
+ * @brief Scale the given Decimal128 by a power of ten
+ *
+ * @param fac The value being scaled
+ * @param exp The exponent: 10^exp is the scale factor
+ * @param rounding Rounding behavior
+ * @param flags Control/result flags
+ * @return mc_dec128 The product
+ */
+static inline mc_dec128
+mc_dec128_scale_ex (mc_dec128 fac,
+ long int exp,
+ mc_dec128_rounding_mode rounding,
+ mc_dec128_flagset *flags)
+{
+ extern mc_dec128 bid128_scalbln (
+ mc_dec128 fac, long int, mc_dec128_rounding_mode, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ return bid128_scalbln (fac, exp, rounding, flags ? flags : &zero_flags);
+}
+
+/**
+ * @brief Scale the given Decimal128 by a power of ten
+ *
+ * @param fac The value being scaled
+ * @param exp The exponent: 10^exp is the scale factor
+ * @return mc_dec128 The product
+ */
+static inline mc_dec128
+mc_dec128_scale (mc_dec128 fac, long int exp)
+{
+ return mc_dec128_scale_ex (fac, exp, MC_DEC128_ROUND_DEFAULT, NULL);
+}
+
+/// The result of a dec_128 modf operation
+typedef struct mc_dec128_modf_result {
+ /// The whole part of the result
+ mc_dec128 whole;
+ /// The fractional part of the result
+ mc_dec128 frac;
+} mc_dec128_modf_result;
+
+/**
+ * @brief Split a Decimal128 into its whole and fractional parts.
+ *
+ * The "whole" value is the integral value of the Decimal128 rounded towards
+ * zero. The "frac" part is the remainder after removing the whole.
+ *
+ * @param d The value to inspect
+ * @param flags Results status flags
+ */
+static inline mc_dec128_modf_result
+mc_dec128_modf_ex (mc_dec128 d, mc_dec128_flagset *flags)
+{
+ extern mc_dec128 bid128_modf (
+ mc_dec128 d, mc_dec128 * iptr, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ mc_dec128_modf_result res;
+ res.frac = bid128_modf (d, &res.whole, flags ? flags : &zero_flags);
+ return res;
+}
+
+/**
+ * @brief Split a Decimal128 into its whole and fractional parts.
+ *
+ * The "whole" value is the integral value of the Decimal128 rounded towards
+ * zero. The "frac" part is the remainder after removing the whole.
+ *
+ * @param d The value to inspect
+ */
+static inline mc_dec128_modf_result
+mc_dec128_modf (mc_dec128 d)
+{
+ return mc_dec128_modf_ex (d, NULL);
+}
+
+/**
+ * @brief Compute the "fmod", the remainder after decimal division rounding
+ * towards zero.
+ *
+ * @param numer The dividend of the modulus
+ * @param denom The divisor of the modulus
+ * @param flags Control/status flags
+ */
+static inline mc_dec128
+mc_dec128_fmod_ex (mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags)
+{
+ extern mc_dec128 bid128_fmod (
+ mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ return bid128_fmod (numer, denom, flags ? flags : &zero_flags);
+}
+
+/**
+ * @brief Compute the "fmod", the remainder after decimal division rounding
+ * towards zero.
+ *
+ * @param numer The dividend of the modulus
+ * @param denom The divisor of the modulus
+ */
+static inline mc_dec128
+mc_dec128_fmod (mc_dec128 numer, mc_dec128 denom)
+{
+ return mc_dec128_fmod_ex (numer, denom, NULL);
+}
+
+/**
+ * @brief Obtain the a 64-bit binary integer value for the given Decimal128
+ * value, nearest rounding toward zero.
+ *
+ * @param d The value to inspect
+ * @param flags Control/status flags
+ */
+static inline int64_t
+mc_dec128_to_int64_ex (mc_dec128 d, mc_dec128_flagset *flags)
+{
+ extern int64_t bid128_to_int64_int (mc_dec128 d, mc_dec128_flagset *);
+ mc_dec128_flagset zero_flags = {0};
+ return bid128_to_int64_int (d, flags ? flags : &zero_flags);
+}
+
+/**
+ * @brief Obtain the a 64-bit binary integer value for the given Decimal128
+ * value, nearest rounding toward zero.
+ *
+ * @param d The value to inspect
+ */
+static inline int64_t
+mc_dec128_to_int64 (mc_dec128 d)
+{
+ return mc_dec128_to_int64_ex (d, NULL);
+}
+
+/// Constants for inspection/deconstruction of Decimal128
+enum {
+ /// Least non-canonical combination bits value
+ MC_DEC128_COMBO_NONCANONICAL = 3 << 15,
+ /// Least combination value indicating infinity
+ MC_DEC128_COMBO_INFINITY = 0x1e << 12,
+ /// The greatest Decimal128 biased exponent
+ MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144,
+ /// The exponent bias of Decimal128
+ MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits
+ /// Minimum exponent value (without bias)
+ MC_DEC_MIN_EXPONENT = -6143,
+ /// Maximum exponent value (without bias)
+ MC_DEC_MAX_EXPONENT = 6144,
+};
+
+/// Obtain the value of the combination bits of a decimal128
+static inline uint32_t
+mc_dec128_combination (mc_dec128 d)
+{
+ // Grab the high 64 bits:
+ uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
+ // Sign is the 64th bit:
+ int signpos = 64 - 1;
+ // Combo is the next 16 bits:
+ int fieldpos = signpos - 17;
+ int fieldmask = (1 << 17) - 1;
+ return (uint32_t) ((hi >> fieldpos) & (uint32_t) fieldmask);
+}
+
+/**
+ * @brief Obtain the value of the high 49 bits of the Decimal128 coefficient
+ */
+static inline uint64_t
+mc_dec128_coeff_high (mc_dec128 d)
+{
+ uint64_t hi_field_mask = (1ull << 49) - 1;
+ uint32_t combo = mc_dec128_combination (d);
+ if (combo < MC_DEC128_COMBO_NONCANONICAL) {
+ uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
+ return hi & hi_field_mask;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * @brief Obtain the value of the low 64 bits of the Decimal128 coefficient
+ */
+static inline uint64_t
+mc_dec128_coeff_low (mc_dec128 d)
+{
+ uint32_t combo = mc_dec128_combination (d);
+ if (combo < MC_DEC128_COMBO_NONCANONICAL) {
+ uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1];
+ return lo;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * @brief Obtain the full coefficient of the given Decimal128 number. Requires a
+ * 128-bit integer.
+ */
+static inline mlib_int128
+mc_dec128_coeff (mc_dec128 d)
+{
+ // Hi bits
+ uint64_t hi = mc_dec128_coeff_high (d);
+ // Lo bits
+ uint64_t lo = mc_dec128_coeff_low (d);
+ // Shift and add
+ mlib_int128 hi_128 = mlib_int128_lshift (MLIB_INT128_CAST (hi), 64);
+ return mlib_int128_add (hi_128, MLIB_INT128_CAST (lo));
+}
+
+/**
+ * @brief Obtain the biased value of the Decimal128 exponent.
+ *
+ * The value is "biased" in that its binary value not actually zero for 10^0. It
+ * is offset by half the exponent range (the "bias") so it can encode the full
+ * positive and negative exponent range. The bias value is defined as
+ * MC_DEC128_EXPONENT_BIAS.
+ */
+static inline uint32_t
+mc_dec128_get_biased_exp (mc_dec128 d)
+{
+ uint32_t combo = mc_dec128_combination (d);
+ if (combo < MC_DEC128_COMBO_NONCANONICAL) {
+ return combo >> 3;
+ }
+ if (combo >= MC_DEC128_COMBO_INFINITY) {
+ return MC_DEC128_MAX_BIASED_EXPONENT + 1;
+ } else {
+ return (combo >> 1) & ((1 << 14) - 1);
+ }
+}
+
+/// Create a decimal string from a dec128 number. The result must be freed.
+static inline char *
+mc_dec128_to_new_decimal_string (mc_dec128 d)
+{
+ if (mc_dec128_is_zero (d)) {
+ // Just return "0"
+ char *s = (char *) calloc (2, 1);
+ if (s) {
+ s[0] = '0';
+ }
+ return s;
+ }
+
+ if (mc_dec128_is_negative (d)) {
+ // Negate the result, return a string with a '-' prefix
+ d = mc_dec128_negate (d);
+ char *s = mc_dec128_to_new_decimal_string (d);
+ if (!s) {
+ return NULL;
+ }
+ char *s1 = (char *) calloc (strlen (s) + 2, 1);
+ if (s1) {
+ s1[0] = '-';
+ strcpy (s1 + 1, s);
+ }
+ free (s);
+ return s1;
+ }
+
+ if (mc_dec128_is_inf (d) || mc_dec128_is_nan (d)) {
+ const char *r = mc_dec128_is_inf (d) ? "Infinity" : "NaN";
+ char *c = (char *) calloc (strlen (r) + 1, 1);
+ if (c) {
+ strcpy (c, r);
+ }
+ return c;
+ }
+
+ const char DIGITS[] = "0123456789";
+ const mc_dec128 TEN = MC_DEC128_C (10);
+
+ // Format the whole and fractional part separately.
+ mc_dec128_modf_result modf = mc_dec128_modf (d);
+
+ if (mc_dec128_is_zero (modf.frac)) {
+ // This is a non-zero integer
+ // Allocate enough digits:
+ mc_dec128 log10 = mc_dec128_modf (mc_dec128_log10 (d)).whole;
+ int64_t ndigits = mc_dec128_to_int64 (log10) + 1;
+ // +1 for null
+ char *strbuf = (char *) calloc ((size_t) (ndigits + 1), 1);
+ if (strbuf) {
+ // Write the string backwards:
+ char *optr = strbuf + ndigits - 1;
+ while (!mc_dec128_is_zero (modf.whole)) {
+ mc_dec128 rem = mc_dec128_fmod (modf.whole, TEN);
+ int64_t remi = mc_dec128_to_int64 (rem);
+ *optr-- = DIGITS[remi];
+ // Divide ten
+ modf = mc_dec128_modf (mc_dec128_div (modf.whole, TEN));
+ }
+ }
+ return strbuf;
+ } else if (mc_dec128_is_zero (modf.whole)) {
+ // This is only a fraction (less than one, but more than zero)
+ while (!mc_dec128_is_zero (mc_dec128_modf (d).frac)) {
+ d = mc_dec128_mul (d, TEN);
+ }
+ // 'd' is now a whole number
+ char *part = mc_dec128_to_new_decimal_string (d);
+ if (!part) {
+ return NULL;
+ }
+ char *buf = (char *) calloc (strlen (part) + 3, 1);
+ if (buf) {
+ buf[0] = '0';
+ buf[1] = '.';
+ strcpy (buf + 2, part);
+ }
+ free (part);
+ return buf;
+ } else {
+ // We have both a whole part and a fractional part
+ char *whole = mc_dec128_to_new_decimal_string (modf.whole);
+ if (!whole) {
+ return NULL;
+ }
+ char *frac = mc_dec128_to_new_decimal_string (modf.frac);
+ if (!frac) {
+ free (whole);
+ return NULL;
+ }
+ char *ret = (char *) calloc (strlen (whole) + strlen (frac) + 1, 1);
+ if (ret) {
+ char *out = ret;
+ strcpy (out, whole);
+ out += strlen (whole);
+ // "frac" contains a leading zero, which we don't want
+ strcpy (out, frac + 1);
+ }
+ free (whole);
+ free (frac);
+ return ret;
+ }
+}
+
+static inline mc_dec128
+mc_dec128_from_bson_iter (bson_iter_t *it)
+{
+ bson_decimal128_t b;
+ if (!bson_iter_decimal128 (it, &b)) {
+ mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
+ return nan;
+ }
+ mc_dec128 ret;
+ memcpy (&ret, &b, sizeof b);
+ return ret;
+}
+
+static inline bson_decimal128_t
+mc_dec128_to_bson_decimal128 (mc_dec128 v)
+{
+ bson_decimal128_t ret;
+ memcpy (&ret, &v, sizeof ret);
+ return ret;
+}
+
+MLIB_C_LINKAGE_END
+
+#endif // MC_DEC128_H_INCLUDED
diff --git a/src/third_party/libmongocrypt/dist/src/mc-dec128.test.cpp b/src/third_party/libmongocrypt/dist/src/mc-dec128.test.cpp
new file mode 100644
index 00000000000..b5bd0bebcb0
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mc-dec128.test.cpp
@@ -0,0 +1,72 @@
+#include <mc-dec128.h>
+
+#include <stdlib.h>
+
+#include <mlib/check.hpp>
+#define CHECK MLIB_CHECK
+
+inline std::ostream &
+operator<< (std::ostream &out, mc_dec128 d) noexcept
+{
+ auto s = mc_dec128_to_new_decimal_string (d);
+ out << s;
+ free (s);
+ return out;
+}
+
+#define OPER(Op, Fn) \
+ inline auto operator Op (mc_dec128 a, mc_dec128 b) noexcept /**/ \
+ ->decltype (mc_dec128_##Fn (a, b)) \
+ { \
+ return mc_dec128_##Fn (a, b); \
+ }
+
+OPER (+, add)
+OPER (-, sub)
+OPER (*, mul)
+OPER (/, div)
+OPER (==, equal)
+OPER (>, greater)
+OPER (<, less)
+
+int
+main ()
+{
+ mc_dec128 a = MC_DEC128_ZERO;
+ CHECK (mc_dec128_is_zero (a));
+
+ mc_dec128 b = MC_DEC128_ZERO;
+ mc_dec128 c = a * b;
+ CHECK (c == MC_DEC128_ZERO);
+ CHECK (mc_dec128_is_zero (c));
+
+ b = MC_DEC128_C (1);
+ // 0 + 1 = 1
+ c = a + b;
+ CHECK (c == MC_DEC128_C (1));
+
+ // 1 + 1 = 2
+ c = b + b;
+ CHECK (c == MC_DEC128_C (2));
+
+ // 2 * 2 = 4
+ c = c * c;
+ CHECK (c == MC_DEC128_C (4));
+
+ // (4 + 1) / 2 = 2.5
+ c = (c + MC_DEC128_C (1)) / MC_DEC128_C (2);
+ CHECK (c == mc_dec128_from_string ("2.5"));
+
+ mc_dec128_string s = mc_dec128_to_string (c);
+ CHECK (std::string (s.str) == "+25E-1");
+
+ char *str = mc_dec128_to_new_decimal_string (c);
+ CHECK (std::string (str) == "2.5");
+ free (str);
+
+ mc_dec128 infin = MC_DEC128_POSITIVE_INFINITY;
+ CHECK (mc_dec128_is_inf (infin));
+
+ mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
+ CHECK (mc_dec128_is_nan (nan));
+}
diff --git a/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev-private.h b/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev-private.h
index e1309821068..b8c771b3c41 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev-private.h
@@ -88,10 +88,10 @@ typedef struct _mc_FLE2IndexedEqualityEncryptedValue_t
mc_FLE2IndexedEncryptedValue_t;
struct _mc_FLE2IndexedEqualityEncryptedValueTokens {
+ uint64_t counter;
_mongocrypt_buffer_t edc;
_mongocrypt_buffer_t esc;
_mongocrypt_buffer_t ecc;
- uint64_t counter;
};
typedef struct _mc_FLE2IndexedEqualityEncryptedValueTokens
@@ -103,11 +103,34 @@ mc_FLE2IndexedEncryptedValue_new (void);
mc_FLE2IndexedEqualityEncryptedValueTokens *
mc_FLE2IndexedEqualityEncryptedValueTokens_new (void);
+/**
+ * This function is used by the server codebase.
+ */
+bool
+mc_FLE2IndexedEqualityEncryptedValueTokens_init_from_buffer (
+ mc_FLE2IndexedEqualityEncryptedValueTokens *tokens,
+ _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status);
+
bool
mc_FLE2IndexedEncryptedValue_parse (mc_FLE2IndexedEncryptedValue_t *iev,
const _mongocrypt_buffer_t *buf,
mongocrypt_status_t *status);
+/**
+ * This function is used by the server codebase.
+ */
+bool
+mc_FLE2IndexedEncryptedValue_write (
+ _mongocrypt_crypto_t *crypto,
+ const bson_type_t original_bson_type,
+ const _mongocrypt_buffer_t *S_KeyId,
+ const _mongocrypt_buffer_t *ClientEncryptedValue,
+ mc_ServerDataEncryptionLevel1Token_t *token,
+ mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens,
+ _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status);
+
/* mc_FLE2IndexedEncryptedValue_get_original_bson_type returns
* original_bson_type. Returns 0 and sets @status on error.
* It is an error to call before mc_FLE2IndexedEncryptedValue_parse. */
@@ -134,7 +157,10 @@ mc_FLE2IndexedEncryptedValue_add_S_Key (_mongocrypt_crypto_t *crypto,
/* mc_FLE2IndexedEncryptedValue_decrypt decrypts InnerEncrypted with the
* ServerDataEncryptionLevel1Token on the server-side. Returns false and sets
* @status on error. It is an error to call before
- * mc_FLE2IndexedEncryptedValue_parse. */
+ * mc_FLE2IndexedEncryptedValue_parse.
+ *
+ * This function is used by the server codebase.
+ */
bool
mc_FLE2IndexedEncryptedValue_decrypt_equality (
_mongocrypt_crypto_t *crypto,
@@ -168,6 +194,13 @@ const _mongocrypt_buffer_t *
mc_FLE2IndexedEncryptedValue_get_ClientValue (
const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status);
+/**
+ * This function is used by the server codebase.
+ */
+const _mongocrypt_buffer_t *
+mc_FLE2IndexedEncryptedValue_get_ClientEncryptedValue (
+ const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status);
+
void
mc_FLE2IndexedEncryptedValue_destroy (mc_FLE2IndexedEncryptedValue_t *iev);
diff --git a/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev.c b/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev.c
index 2f8767cf055..ef6e28689b0 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-fle2-payload-iev.c
@@ -14,18 +14,21 @@
* limitations under the License.
*/
+#include "mongocrypt-buffer-private.h"
#include "mongocrypt-private.h"
#include "mc-fle-blob-subtype-private.h"
#include "mc-fle2-payload-iev-private.h"
#include "mc-tokens-private.h"
#include "mc-reader-private.h"
+#include "mc-writer-private.h"
#include <stdint.h>
#define CHECK_AND_RETURN(x) \
if (!(x)) { \
return false; \
}
+
struct _mc_FLE2IndexedEqualityEncryptedValue_t {
_mongocrypt_buffer_t S_KeyId;
_mongocrypt_buffer_t InnerEncrypted;
@@ -53,6 +56,240 @@ mc_FLE2IndexedEqualityEncryptedValueTokens_new (void)
}
bool
+mc_FLE2IndexedEqualityEncryptedValueTokens_init_from_buffer (
+ mc_FLE2IndexedEqualityEncryptedValueTokens *tokens,
+ _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (tokens);
+ BSON_ASSERT_PARAM (buf);
+
+ mc_reader_t reader;
+ mc_reader_init_from_buffer (&reader, buf, __FUNCTION__);
+
+ CHECK_AND_RETURN (mc_reader_read_u64 (&reader, &tokens->counter, status));
+
+ CHECK_AND_RETURN (
+ mc_reader_read_prfblock_buffer (&reader, &tokens->edc, status));
+
+ CHECK_AND_RETURN (
+ mc_reader_read_prfblock_buffer (&reader, &tokens->esc, status));
+
+ CHECK_AND_RETURN (
+ mc_reader_read_prfblock_buffer (&reader, &tokens->ecc, status));
+
+ return true;
+}
+
+static bool
+mc_fle2IndexedEncryptedValue_encrypt (
+ _mongocrypt_crypto_t *crypto,
+ const _mongocrypt_buffer_t *ClientEncryptedValue,
+ mc_ServerDataEncryptionLevel1Token_t *token,
+ mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens,
+ _mongocrypt_buffer_t *out,
+ mongocrypt_status_t *status);
+
+bool
+safe_uint32_t_sum (const uint32_t a,
+ const uint32_t b,
+ uint32_t *out,
+ mongocrypt_status_t *status)
+{
+ if (a > UINT32_MAX - b) {
+ CLIENT_ERR ("safe_uint32_t_sum overflow, %" PRIu32 ", %" PRIu32, a, b);
+ return false;
+ }
+ *out = a + b;
+ return true;
+}
+
+bool
+mc_FLE2IndexedEncryptedValue_write (
+ _mongocrypt_crypto_t *crypto,
+ const bson_type_t original_bson_type,
+ const _mongocrypt_buffer_t *S_KeyId,
+ const _mongocrypt_buffer_t *ClientEncryptedValue,
+ mc_ServerDataEncryptionLevel1Token_t *token,
+ mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens,
+ _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status)
+{
+#define CHECK_AND_GOTO(x) \
+ if (!(x)) { \
+ goto cleanup; \
+ }
+
+ bool ok = false;
+
+ BSON_ASSERT_PARAM (crypto);
+ BSON_ASSERT_PARAM (index_tokens);
+ BSON_ASSERT_PARAM (S_KeyId);
+ BSON_ASSERT_PARAM (ClientEncryptedValue);
+ BSON_ASSERT_PARAM (token);
+ BSON_ASSERT_PARAM (index_tokens);
+ BSON_ASSERT_PARAM (buf);
+
+ if (ClientEncryptedValue->len == 0) {
+ CLIENT_ERR (
+ "mc_FLE2IndexedEncryptedValue_write iev must have an encrypted value");
+ return ok;
+ }
+
+ if (S_KeyId->len == 0) {
+ CLIENT_ERR (
+ "mc_FLE2IndexedEncryptedValue_write iev SKeyId must have value");
+ return ok;
+ }
+
+ _mongocrypt_buffer_t encryption_out;
+ _mongocrypt_buffer_init (&encryption_out);
+
+ CHECK_AND_GOTO (mc_fle2IndexedEncryptedValue_encrypt (crypto,
+ ClientEncryptedValue,
+ token,
+ index_tokens,
+ &encryption_out,
+ status));
+ uint32_t expected_plaintext_size = 0;
+ CHECK_AND_GOTO (safe_uint32_t_sum (
+ ClientEncryptedValue->len,
+ (uint32_t) (sizeof (uint64_t) * 2 + sizeof (uint32_t) * 3),
+ &expected_plaintext_size,
+ status));
+
+ uint32_t expected_cipher_size = _mongocrypt_fle2_calculate_ciphertext_len (
+ expected_plaintext_size, status);
+
+ if (expected_cipher_size == 0) {
+ CHECK_AND_GOTO (false);
+ }
+
+ uint32_t expected_buf_size = 0;
+ CHECK_AND_RETURN (safe_uint32_t_sum (expected_cipher_size,
+ (uint32_t) (1 + sizeof (S_KeyId)),
+ &expected_buf_size,
+ status));
+
+ if (buf->len < expected_buf_size) {
+ CLIENT_ERR (
+ "mc_FLE2IndexedEncryptedValue_write buf is not large enough for iev");
+ CHECK_AND_GOTO (false);
+ }
+
+ mc_writer_t writer;
+ mc_writer_init_from_buffer (&writer, buf, __FUNCTION__);
+
+ const uint8_t subtype =
+ (uint8_t) MC_SUBTYPE_FLE2IndexedEqualityEncryptedValue;
+
+ if ((original_bson_type < 0) || (original_bson_type > 0xFF)) {
+ CLIENT_ERR ("Field 't' must be a valid BSON type, got: %d",
+ original_bson_type);
+ CHECK_AND_GOTO (false);
+ }
+
+ const uint8_t bson_type = (uint8_t) original_bson_type;
+
+ CHECK_AND_GOTO (mc_writer_write_u8 (
+ &writer, subtype, status));
+ CHECK_AND_GOTO (mc_writer_write_buffer (
+ &writer, S_KeyId, S_KeyId->len, status));
+ CHECK_AND_GOTO (mc_writer_write_u8 (
+ &writer, bson_type, status));
+
+ CHECK_AND_GOTO (mc_writer_write_buffer (
+ &writer, &encryption_out, encryption_out.len, status));
+
+ ok = true;
+
+cleanup:
+ _mongocrypt_buffer_cleanup (&encryption_out);
+ return ok;
+#undef CHECK_AND_GOTO
+}
+
+static bool
+mc_fle2IndexedEncryptedValue_encrypt (
+ _mongocrypt_crypto_t *crypto,
+ const _mongocrypt_buffer_t *ClientEncryptedValue,
+ mc_ServerDataEncryptionLevel1Token_t *token,
+ mc_FLE2IndexedEqualityEncryptedValueTokens *index_tokens,
+ _mongocrypt_buffer_t *out,
+ mongocrypt_status_t *status)
+{
+#define CHECK_AND_GOTO(x) \
+ if (!(x)) { \
+ goto cleanup; \
+ }
+
+ bool ok = false;
+ _mongocrypt_buffer_t in;
+ _mongocrypt_buffer_t iv;
+
+ _mongocrypt_buffer_init (&in);
+ _mongocrypt_buffer_init_size (&iv, MONGOCRYPT_IV_LEN);
+
+ uint32_t expected_buf_size = 0;
+ CHECK_AND_GOTO (
+ safe_uint32_t_sum (ClientEncryptedValue->len,
+ (uint32_t) (sizeof (uint64_t) * 2 + (32 * 3)),
+ &expected_buf_size,
+ status));
+
+ _mongocrypt_buffer_resize (&in, expected_buf_size);
+
+ uint32_t ciphertext_len =
+ _mongocrypt_fle2_calculate_ciphertext_len (expected_buf_size, status);
+
+ if (ciphertext_len == 0) {
+ return false;
+ }
+
+ _mongocrypt_buffer_resize (out, ciphertext_len);
+
+ mc_writer_t writer;
+ mc_writer_init_from_buffer (&writer, &in, __FUNCTION__);
+
+ uint64_t length;
+ length = ClientEncryptedValue->len;
+ CHECK_AND_GOTO (mc_writer_write_u64 (&writer, length, status));
+
+ CHECK_AND_GOTO (mc_writer_write_buffer (
+ &writer, ClientEncryptedValue, ClientEncryptedValue->len, status));
+
+ CHECK_AND_GOTO (
+ mc_writer_write_u64 (&writer, index_tokens->counter, status));
+
+ CHECK_AND_GOTO (
+ mc_writer_write_prfblock_buffer (&writer, &index_tokens->edc, status));
+
+ CHECK_AND_GOTO (
+ mc_writer_write_prfblock_buffer (&writer, &index_tokens->esc, status));
+
+ CHECK_AND_GOTO (
+ mc_writer_write_prfblock_buffer (&writer, &index_tokens->ecc, status));
+
+ const _mongocrypt_buffer_t *token_buf =
+ mc_ServerDataEncryptionLevel1Token_get (token);
+
+ uint32_t bytes_written;
+
+ CHECK_AND_GOTO (_mongocrypt_random (crypto, &iv, MONGOCRYPT_IV_LEN, status));
+
+ CHECK_AND_GOTO (_mongocrypt_fle2_do_encryption (
+ crypto, &iv, token_buf, &in, out, &bytes_written, status));
+
+ ok = true;
+
+cleanup:
+ _mongocrypt_buffer_cleanup (&iv);
+ _mongocrypt_buffer_cleanup (&in);
+ return ok;
+#undef CHECK_AND_GOTO
+}
+
+bool
mc_FLE2IndexedEncryptedValue_parse (mc_FLE2IndexedEncryptedValue_t *iev,
const _mongocrypt_buffer_t *buf,
mongocrypt_status_t *status)
@@ -228,8 +465,8 @@ mc_FLE2IndexedEncryptedValue_decrypt (
uint64_t expected_length =
mc_reader_get_consumed_length (&reader) + length - 16;
if (length > iev->Inner.len || expected_length > iev->Inner.len) {
- CLIENT_ERR ("mc_FLE2IndexedEncryptedValue_add_S_Key expected "
- "byte length >= %" PRIu32 " got: %" PRIu32,
+ CLIENT_ERR ("mc_FLE2IndexedEncryptedValue_decrypt expected "
+ "byte length >= %" PRIu64 " got: %" PRIu32,
expected_length,
iev->Inner.len);
return false;
@@ -327,6 +564,15 @@ mc_FLE2IndexedEqualityEncryptedValue_add_K_Key (
}
const _mongocrypt_buffer_t *
+mc_FLE2IndexedEncryptedValue_get_ClientEncryptedValue (
+ const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (iev);
+
+ return &iev->ClientEncryptedValue;
+}
+
+const _mongocrypt_buffer_t *
mc_FLE2IndexedEncryptedValue_get_ClientValue (
const mc_FLE2IndexedEncryptedValue_t *iev, mongocrypt_status_t *status)
{
diff --git a/src/third_party/libmongocrypt/dist/src/mc-optional-private.h b/src/third_party/libmongocrypt/dist/src/mc-optional-private.h
index 3ce6a0b26d5..506fd063755 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-optional-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-optional-private.h
@@ -20,6 +20,9 @@
#include <stdbool.h>
#include <stdint.h>
+#include "./mc-dec128.h"
+#include "./mlib/int128.h"
+
typedef struct {
bool set;
int32_t value;
@@ -100,4 +103,21 @@ typedef struct {
.set = true, .value = val \
}
+typedef struct {
+ bool set;
+ mc_dec128 value;
+} mc_optional_dec128_t;
+
+#define OPT_MC_DEC128(...) \
+ (mc_optional_dec128_t) \
+ { \
+ .set = true, .value = __VA_ARGS__ \
+ }
+
+
+#define OPT_NULLOPT \
+ { \
+ .set = false \
+ }
+
#endif /* MC_OPTIONAL_PRIVATE_H */
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation-private.h b/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation-private.h
index 033a9f5f8cf..865ff7a88ad 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation-private.h
@@ -21,6 +21,8 @@
#include <stdint.h>
#include "mc-optional-private.h"
#include "mongocrypt-status-private.h"
+#include "mc-dec128.h"
+#include <mlib/int128.h>
// mc_edges_t represents a list of edges.
typedef struct _mc_edges_t mc_edges_t;
@@ -75,24 +77,87 @@ typedef struct {
mc_edges_t *
mc_getEdgesDouble (mc_getEdgesDouble_args_t args, mongocrypt_status_t *status);
+typedef struct {
+ mc_dec128 value;
+ size_t sparsity;
+ mc_optional_dec128_t min, max;
+ mc_optional_uint32_t precision;
+} mc_getEdgesDecimal128_args_t;
+
+mc_edges_t *
+mc_getEdgesDecimal128 (mc_getEdgesDecimal128_args_t args,
+ mongocrypt_status_t *status);
+
+
// count_leading_zeros_u64 returns the number of leading 0 bits of `in`.
-size_t
-mc_count_leading_zeros_u64 (uint64_t in);
+static inline size_t
+mc_count_leading_zeros_u64 (uint64_t in)
+{
+#ifdef __has_builtin
+#if __has_builtin(__builtin_clzl)
+// Pointer-cast to ensure we are speaking the right type
+#ifdef __APPLE__
+ unsigned long long *p = &in;
+ return (size_t) (in ? __builtin_clzll (*p) : 64);
+#else
+ unsigned long *p = &in;
+ return (size_t) (in ? __builtin_clzl (*p) : 64);
+#endif
+#endif
+#endif
+ uint64_t bit = UINT64_C (1) << 63;
+ size_t count = 0;
+ while ((bit & in) == 0 && bit > 0) {
+ bit >>= 1;
+ ++count;
+ }
+ return count;
+}
// count_leading_zeros_u32 returns the number of leading 0 bits of `in`.
-size_t
-mc_count_leading_zeros_u32 (uint32_t in);
+static inline size_t
+mc_count_leading_zeros_u32 (uint32_t in)
+{
+#ifdef __has_builtin
+#if __has_builtin(__builtin_clz)
+ // Pointer-cast to ensure we are speaking the right type
+ unsigned int *p = &in;
+ return (size_t) (in ? __builtin_clz (*p) : 32);
+#endif
+#endif
+ uint32_t bit = UINT32_C (1) << 31;
+ int count = 0;
+ while ((bit & in) == 0 && bit > 0) {
+ bit >>= 1;
+ ++count;
+ }
+ return (size_t) count;
+}
+
+static inline size_t
+mc_count_leading_zeros_u128 (mlib_int128 in)
+{
+ size_t hi = mc_count_leading_zeros_u64 (
+ mlib_int128_to_u64 (mlib_int128_rshift (in, 64)));
+ size_t lo = mc_count_leading_zeros_u64 (mlib_int128_to_u64 (in));
+ return hi + ((hi == 64 ? 1u : 0u) * lo);
+}
+
+typedef struct mc_bitstring {
+ char str[129];
+} mc_bitstring;
// mc_convert_to_bitstring_u64 returns a 64 character string of 1's and 0's
-// representing the bits of `in`. Caller must call `bson_free` on returned
-// value.
-char *
+// representing the bits of `in`
+mc_bitstring
mc_convert_to_bitstring_u64 (uint64_t in);
// mc_convert_to_bitstring_u32 returns a 32 character string of 1's and 0's
-// representing the bits of `in`. Caller must call `bson_free` on returned
-// value.
-char *
+// representing the bits of `in`.
+mc_bitstring
mc_convert_to_bitstring_u32 (uint32_t in);
+mc_bitstring
+mc_convert_to_bitstring_u128 (mlib_int128 i);
+
#endif /* MC_RANGE_EDGE_GENERATION_PRIVATE_H */
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation.c b/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation.c
index 5faffb552bf..caa7e65b2f5 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-edge-generation.c
@@ -89,66 +89,53 @@ mc_edges_destroy (mc_edges_t *edges)
bson_free (edges);
}
-size_t
-mc_count_leading_zeros_u64 (uint64_t in)
-{
- uint64_t bit = UINT64_C (1) << 63;
- size_t count = 0;
- while ((bit & in) == 0 && bit > 0) {
- bit >>= 1;
- ++count;
- }
- return count;
-}
-
-size_t
-mc_count_leading_zeros_u32 (uint32_t in)
-{
- uint32_t bit = UINT32_C (1) << 31;
- size_t count = 0;
- while ((bit & in) == 0 && bit > 0) {
- bit >>= 1;
- ++count;
- }
- return count;
-}
-
-char *
+mc_bitstring
mc_convert_to_bitstring_u64 (uint64_t in)
{
- char *out = bson_malloc (64 + 1);
+ mc_bitstring ret = {{0}};
+ char *out = ret.str;
uint64_t bit = UINT64_C (1) << 63;
- size_t count = 0;
while (bit > 0) {
if (bit & in) {
- out[count] = '1';
+ *out++ = '1';
} else {
- out[count] = '0';
+ *out++ = '0';
}
bit >>= 1;
- ++count;
}
- out[64] = '\0';
- return out;
+ return ret;
}
-char *
+mc_bitstring
mc_convert_to_bitstring_u32 (uint32_t in)
{
- char *out = bson_malloc (32 + 1);
+ mc_bitstring ret = {{0}};
+ char *out = ret.str;
uint32_t bit = UINT32_C (1) << 31;
- size_t count = 0;
while (bit > 0) {
if (bit & in) {
- out[count] = '1';
+ *out++ = '1';
} else {
- out[count] = '0';
+ *out++ = '0';
}
bit >>= 1;
- ++count;
}
- out[32] = '\0';
- return out;
+ return ret;
+}
+
+mc_bitstring
+mc_convert_to_bitstring_u128 (mlib_int128 i)
+{
+ const uint64_t lo = mlib_int128_to_u64 (i);
+ const uint64_t hi = mlib_int128_to_u64 (mlib_int128_rshift (i, 64));
+ mc_bitstring his = mc_convert_to_bitstring_u64 (hi);
+ mc_bitstring los = mc_convert_to_bitstring_u64 (lo);
+ mc_bitstring ret = {{0}};
+ const size_t off =
+ mlib_strnmcopy (ret.str, sizeof ret.str, his.str, sizeof his.str);
+ mlib_strnmcopy (
+ ret.str + off, (sizeof ret.str) - off, los.str, sizeof los.str);
+ return ret;
}
mc_edges_t *
@@ -168,11 +155,10 @@ mc_getEdgesInt32 (mc_getEdgesInt32_args_t args, mongocrypt_status_t *status)
// for consistency with the server implementation.
BSON_ASSERT (got.min == 0);
- char *valueBin = mc_convert_to_bitstring_u32 (got.value);
+ mc_bitstring valueBin = mc_convert_to_bitstring_u32 (got.value);
size_t offset = mc_count_leading_zeros_u32 (got.max);
- const char *leaf = valueBin + offset;
+ const char *leaf = valueBin.str + offset;
mc_edges_t *ret = mc_edges_new (leaf, args.sparsity, status);
- bson_free (valueBin);
return ret;
}
@@ -193,11 +179,10 @@ mc_getEdgesInt64 (mc_getEdgesInt64_args_t args, mongocrypt_status_t *status)
// for consistency with the server implementation.
BSON_ASSERT (got.min == 0);
- char *valueBin = mc_convert_to_bitstring_u64 (got.value);
+ mc_bitstring valueBin = mc_convert_to_bitstring_u64 (got.value);
size_t offset = mc_count_leading_zeros_u64 (got.max);
- const char *leaf = valueBin + offset;
+ const char *leaf = valueBin.str + offset;
mc_edges_t *ret = mc_edges_new (leaf, args.sparsity, status);
- bson_free (valueBin);
return ret;
}
@@ -221,10 +206,35 @@ mc_getEdgesDouble (mc_getEdgesDouble_args_t args, mongocrypt_status_t *status)
// for consistency with the server implementation.
BSON_ASSERT (got.min == 0);
- char *valueBin = mc_convert_to_bitstring_u64 (got.value);
+ mc_bitstring valueBin = mc_convert_to_bitstring_u64 (got.value);
size_t offset = mc_count_leading_zeros_u64 (got.max);
- const char *leaf = valueBin + offset;
+ const char *leaf = valueBin.str + offset;
+ mc_edges_t *ret = mc_edges_new (leaf, args.sparsity, status);
+ return ret;
+}
+
+mc_edges_t *
+mc_getEdgesDecimal128 (mc_getEdgesDecimal128_args_t args,
+ mongocrypt_status_t *status)
+{
+ mc_OSTType_Decimal128 got;
+ if (!mc_getTypeInfoDecimal128 (
+ (mc_getTypeInfoDecimal128_args_t){
+ .value = args.value,
+ .min = args.min,
+ .max = args.max,
+ .precision = args.precision,
+ },
+ &got,
+ status)) {
+ return NULL;
+ }
+
+ BSON_ASSERT (mlib_int128_eq (got.min, MLIB_INT128 (0)));
+
+ mc_bitstring bits = mc_convert_to_bitstring_u128 (got.value);
+ size_t offset = mc_count_leading_zeros_u128 (got.max);
+ const char *leaf = bits.str + offset;
mc_edges_t *ret = mc_edges_new (leaf, args.sparsity, status);
- bson_free (valueBin);
return ret;
}
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-encoding-private.h b/src/third_party/libmongocrypt/dist/src/mc-range-encoding-private.h
index b96f2dfd54a..96840f558e0 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-encoding-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-encoding-private.h
@@ -17,10 +17,14 @@
#ifndef MC_RANGE_ENCODING_PRIVATE_H
#define MC_RANGE_ENCODING_PRIVATE_H
-#include <stdint.h>
#include "mc-optional-private.h"
+#include "mc-dec128.h"
#include "mongocrypt-status-private.h"
+#include <mlib/int128.h>
+
+#include <stdint.h>
+
/* mc-range-encoding-private.h has functions to encode numeric types for
* Queryable Encryption Range queries. It is a translation from server code:
* https://github.com/mongodb/mongo/blob/1364f5c5004ac5503837ac5b315c189625f97269/src/mongo/crypto/fle_crypto.h#L1194-L1196
@@ -92,4 +96,31 @@ mc_getTypeInfoDouble (mc_getTypeInfoDouble_args_t args,
mongocrypt_status_t *status)
MONGOCRYPT_WARN_UNUSED_RESULT;
+/**
+ * @brief OST-encoding of a Decimal128
+ */
+typedef struct {
+ mlib_int128 value, min, max;
+} mc_OSTType_Decimal128;
+
+typedef struct {
+ mc_dec128 value;
+ mc_optional_dec128_t min, max;
+ mc_optional_uint32_t precision;
+} mc_getTypeInfoDecimal128_args_t;
+
+/**
+ * @brief Obtain the OST encoding of a finite Decimal128 value.
+ *
+ * @param out Output for the result
+ * @param status Output for status on error
+ * @retval true On success
+ * @retval false Otherwise
+ */
+bool
+mc_getTypeInfoDecimal128 (mc_getTypeInfoDecimal128_args_t args,
+ mc_OSTType_Decimal128 *out,
+ mongocrypt_status_t *status)
+ MONGOCRYPT_WARN_UNUSED_RESULT;
+
#endif /* MC_RANGE_ENCODING_PRIVATE_H */
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-encoding.c b/src/third_party/libmongocrypt/dist/src/mc-range-encoding.c
index 0d95218e64a..24cf0fdd655 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-encoding.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-encoding.c
@@ -230,7 +230,7 @@ mc_getTypeInfoDouble (mc_getTypeInfoDouble_args_t args,
uint32_t bits_range;
if (args.precision.set) {
// Subnormal representations can support up to 5x10^-324 as a number
- if (args.precision.value < 0 || args.precision.value > 324) {
+ if (args.precision.value > 324) {
CLIENT_ERR (
"Precision must be between 0 and 324 inclusive, got: %" PRIu32,
args.precision.value);
@@ -313,3 +313,303 @@ mc_getTypeInfoDouble (mc_getTypeInfoDouble_args_t args,
return true;
}
+
+/**
+ * @brief There is no shipped algorithm for creating a full 128-bit integer from
+ * a Decimal128, but it's easy enough to write one of our own.
+ *
+ * @param dec
+ * @return mlib_int128
+ */
+static mlib_int128
+dec128_to_int128 (mc_dec128 dec)
+{
+ // Only normal numbers
+ BSON_ASSERT (mc_dec128_is_finite (dec));
+ BSON_ASSERT (!mc_dec128_is_nan (dec));
+ // We don't support negative numbers
+ BSON_ASSERT (!mc_dec128_is_negative (dec));
+ // There is no fractional part:
+ BSON_ASSERT (mc_dec128_is_zero (mc_dec128_modf (dec).frac));
+
+ mlib_int128 ret = mc_dec128_coeff (dec);
+
+ // Scale the resulting number by a power of ten matching the exponent of the
+ // Decimal128:
+ int32_t exp =
+ ((int32_t) mc_dec128_get_biased_exp (dec)) - MC_DEC128_EXPONENT_BIAS;
+ // We will scale up/down based on whether it is negative:
+ mlib_int128 e1 = mlib_int128_pow10 ((uint8_t) abs (exp));
+ if (exp < 0) {
+ ret = mlib_int128_div (ret, e1);
+ } else {
+ ret = mlib_int128_mul (ret, e1);
+ }
+
+ return ret;
+}
+
+bool
+mc_getTypeInfoDecimal128 (mc_getTypeInfoDecimal128_args_t args,
+ mc_OSTType_Decimal128 *out,
+ mongocrypt_status_t *status)
+{
+ /// Basic param checks
+ if (args.min.set != args.max.set || args.min.set != args.precision.set) {
+ CLIENT_ERR (
+ "min, max, and precision must all be set or must all be unset");
+ return false;
+ }
+
+ // We only accept normal numbers
+ if (mc_dec128_is_inf (args.value) || mc_dec128_is_nan (args.value)) {
+ CLIENT_ERR ("Infinity and Nan Decimal128 values are not supported.");
+ return false;
+ }
+
+ // Check boundary if a range is set
+ if (args.min.set) {
+ // [min,max] must be valid
+ if (mc_dec128_greater_equal (args.min.value, args.max.value)) {
+ CLIENT_ERR (
+ "The minimum value must be less than the maximum value, got "
+ "min: %s, max: %s",
+ mc_dec128_to_string (args.min.value).str,
+ mc_dec128_to_string (args.max.value).str);
+ return false;
+ }
+
+ // Value must be within [min,max)
+ if (mc_dec128_greater (args.value, args.max.value) ||
+ mc_dec128_less (args.value, args.min.value)) {
+ CLIENT_ERR ("Value must be greater than or equal to the minimum value "
+ "and less than or equal to the maximum value, got "
+ "min: %s, max: %s, value: %s",
+ mc_dec128_to_string (args.min.value).str,
+ mc_dec128_to_string (args.max.value).str,
+ mc_dec128_to_string (args.value).str);
+ return false;
+ }
+ }
+
+ // Should we use precision mode?
+ //
+ // When we use precision mode, we try to represent as a decimal128 value that
+ // fits in [-2^127, 2^127] (i.e. is a valid int128)
+ //
+ // This check determines if we can represent any precision-truncated value as
+ // a 128-bit integer I.e. Is ((ub - lb) * 10^precision) < 128 bits.
+ //
+ // It is important that we determine whether a range and its precision would
+ // fit, regardless of the value to be encoded, because the encoding for
+ // precision-truncated-decimal128 is incompatible with the encoding of the
+ // full range.
+ bool use_precision_mode = false;
+ // The number of bits required to hold the result (used for precision mode)
+ uint8_t bits_range = 0;
+ if (args.precision.set) {
+ // Subnormal representations can support up to 5x10^-6182 as a number
+ if (args.precision.value > 6182) {
+ CLIENT_ERR (
+ "Precision must be between 0 and 6182 inclusive, got: %" PRIu32,
+ args.precision.value);
+ return false;
+ }
+
+ // max - min
+ mc_dec128 bounds_n1 = mc_dec128_sub (args.max.value, args.min.value);
+ // The size of [min, max]: (max - min) + 1
+ mc_dec128 bounds = mc_dec128_add (bounds_n1, MC_DEC128_ONE);
+
+ // We can overflow if max = max_dec128 and min = min_dec128 so make sure
+ // we have finite number after we do subtraction
+ if (mc_dec128_is_finite (bounds)) {
+ // This creates a range which is wider then we permit by our min/max
+ // bounds check with the +1 but it is as the algorithm is written in
+ // WRITING-11907.
+ mc_dec128 precision_scaled_bounds =
+ mc_dec128_scale (bounds, args.precision.value);
+ /// The number of bits required to hold the result for the given
+ /// precision (as decimal)
+ mc_dec128 bits_range_dec = mc_dec128_log2 (precision_scaled_bounds);
+
+ if (mc_dec128_is_finite (bits_range_dec) &&
+ mc_dec128_less (bits_range_dec, MC_DEC128 (128))) {
+ // We need fewer than 128 bits to hold the result. But round up,
+ // just to be sure:
+ int64_t r = mc_dec128_to_int64 (
+ mc_dec128_round_integral_positive (bits_range_dec));
+ BSON_ASSERT (r >= 0);
+ BSON_ASSERT (r <= UINT8_MAX);
+ // We've computed the proper 'bits_range'
+ bits_range = (uint8_t) r;
+
+ if (bits_range < 128) {
+ use_precision_mode = true;
+ }
+ }
+ }
+ }
+
+ // Constant zero
+ const mlib_int128 i128_zero = MLIB_INT128 (0);
+ // Constant 1
+ const mlib_int128 i128_one = MLIB_INT128 (1);
+ // Constant 10
+ const mlib_int128 i128_ten = MLIB_INT128 (10);
+ // Constant: 2^127
+ const mlib_int128 i128_2pow127 = mlib_int128_lshift (i128_one, 127);
+ // ↑ Coincidentally has the same bit pattern as INT128_SMIN, but we're
+ // treating it as an unsigned number here, so don't get confused!
+
+ if (use_precision_mode) {
+ BSON_ASSERT (args.precision.set);
+ // Example value: 31.4159
+ // Example Precision = 2
+
+ // Shift the number up
+ // Returns: 3141.9
+ mc_dec128 valScaled = mc_dec128_scale (args.value, args.precision.value);
+
+ // Round the number down
+ // Returns 3141.0
+ mc_dec128 valTrunc = mc_dec128_round_integral_zero (valScaled);
+
+ // Shift the number down
+ // Returns: 31.41
+ mc_dec128 v_prime =
+ mc_dec128_scale (valTrunc, -(int32_t) args.precision.value);
+
+ // Adjust the number by the lower bound
+ // Make it an integer by scaling the number
+ //
+ // Returns 3141.0
+ mc_dec128 v_prime2 = mc_dec128_scale (
+ mc_dec128_sub (v_prime, args.min.value), args.precision.value);
+ // Round the number down again. min may have a fractional value with more
+ // decimal places than the precision (e.g. .001). Subtracting min may have
+ // resulted in v_prime2 with a non-zero fraction. v_prime2 is expected to
+ // have no fractional value when converting to int128.
+ v_prime2 = mc_dec128_round_integral_zero (v_prime2);
+
+ BSON_ASSERT (mc_dec128_less (mc_dec128_log2 (v_prime2), MC_DEC128 (128)));
+
+ // Resulting OST maximum
+ mlib_int128 ost_max =
+ mlib_int128_sub (mlib_int128_pow2 (bits_range), i128_one);
+
+ // Now we need to get the Decimal128 out as a 128-bit integer
+ // But Decimal128 does not support conversion to Int128.
+ //
+ // If we think the Decimal128 fits in the range, based on the maximum
+ // value, we try to convert to int64 directly.
+ if (bits_range < 64) {
+ // Try conversion to int64, it may fail but since it is easy we try
+ // this first.
+ mc_dec128_flagset flags = {0};
+ int64_t as64 = mc_dec128_to_int64_ex (v_prime2, &flags);
+ if (flags.bits == 0) {
+ // No error. It fits
+ *out = (mc_OSTType_Decimal128){
+ .value = MLIB_INT128_CAST (as64),
+ .min = i128_zero,
+ .max = ost_max,
+ };
+ return true;
+ } else {
+ // Conversion failure to 64-bit. Possible overflow, imprecision,
+ // etc. Fallback to slower dec128_to_int128
+ }
+ }
+
+ mlib_int128 u_ret = dec128_to_int128 (v_prime2);
+
+ *out = (mc_OSTType_Decimal128){
+ .value = u_ret,
+ .min = i128_zero,
+ .max = ost_max,
+ };
+
+ return true;
+ }
+
+ // The coefficient of the number, without exponent/sign
+ const mlib_int128 coeff = mc_dec128_coeff (args.value);
+
+ if (mlib_int128_eq (coeff, i128_zero)) {
+ // If the coefficient is zero, the result is encoded as the midpoint
+ // between zero and 2^128-1
+ *out = (mc_OSTType_Decimal128){
+ .value = i128_2pow127,
+ .min = i128_zero,
+ .max = MLIB_INT128_UMAX,
+ };
+ return true;
+ }
+
+ // Coefficient is an unsigned value. We'll later scale our answer based on
+ // the sign of the actual Decimal128
+ const bool isNegative = mc_dec128_is_negative (args.value);
+
+ // cMax = 10^34 - 1 (The largest integer representable in Decimal128)
+ const mlib_int128 cMax =
+ mlib_int128_sub (mlib_int128_pow10 (34), MLIB_INT128_CAST (1));
+ const mlib_int128 cMax_div_ten = mlib_int128_div (cMax, i128_ten);
+
+ // The biased exponent from the decimal number. The paper refers to the
+ // expression (e - e_min), which is the value of the biased exponent.
+ const uint32_t exp_biased = mc_dec128_get_biased_exp (args.value);
+
+ // ρ (rho) is the greatest integer such that: coeff×10^ρ <= cMax
+ unsigned rho = 0;
+ // Keep track of the subexpression coeff×10^ρ rather than recalculating it
+ // time.
+ // Initially: (ρ = 0) -> (10^ρ = 1) -> (coeff×10^ρ = coeff×1 = coeff):
+ mlib_int128 coeff_scaled = coeff;
+ // Calculate ρ: This could be done using a log10 with a division, but that
+ // is far more work than just a few multiplications.
+ // While: coeff×ten^ρ < cMax/10:
+ while (mlib_int128_ucmp (coeff_scaled, cMax_div_ten) < 0) {
+ // Increase rho until we pass cMax/10
+ rho++;
+ // Scale our computed subexpression rather than fully recomputing it
+ coeff_scaled = mlib_int128_mul (coeff_scaled, i128_ten);
+ }
+
+ // No multiplication by 10 should ever send us from N < cMax/10 to N > cMax
+ BSON_ASSERT (mlib_int128_ucmp (coeff_scaled, cMax) <= 0);
+
+ mlib_int128 result;
+ if (rho <= exp_biased) {
+ // ρ is less-than/equal to the exponent with bias.
+
+ // Diff between the biased exponent and ρ.
+ // Value in paper is spelled "e - e_min - ρ"
+ const uint32_t exp_diff = exp_biased - (uint32_t) rho;
+ // cMax * (exp_diff)
+ const mlib_int128 cmax_scaled =
+ mlib_int128_mul (cMax, MLIB_INT128_CAST (exp_diff));
+ // coeff * 10^rho * cMax * (exp_biased - rho)
+ result = mlib_int128_add (coeff_scaled, cmax_scaled);
+ } else {
+ const mlib_int128 biased_scale = mlib_int128_pow10 ((uint8_t) exp_biased);
+ result = mlib_int128_mul (biased_scale, coeff);
+ }
+
+ // Always add 2^127:
+ result = mlib_int128_add (result, i128_2pow127);
+
+ if (isNegative) {
+ // We calculated the value of the positive coefficient, but the decimal is
+ // negative. That's okay: Just flip the sign of the encoded result:
+ result = mlib_int128_negate (result);
+ }
+
+ *out = (mc_OSTType_Decimal128){
+ .value = result,
+ .min = i128_zero,
+ .max = MLIB_INT128_UMAX,
+ };
+
+ return true;
+}
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-mincover-generator.template.h b/src/third_party/libmongocrypt/dist/src/mc-range-mincover-generator.template.h
index 9b348a156f3..54fa345ae69 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-mincover-generator.template.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-mincover-generator.template.h
@@ -16,9 +16,6 @@
// mc-range-mincover-generator.template.h is meant to be included in another
// source file.
-#ifndef BITS
-#error "must be included with BITS defined"
-#endif
// TODO: replace `CONCAT` with `BSON_CONCAT` after libbson dependency is
// upgraded to 1.20.0 or higher.
@@ -32,11 +29,75 @@
#define CONCAT3(a, b, c) CONCAT (a, CONCAT (b, c))
#endif
-#define UINT_T CONCAT3 (uint, BITS, _t)
-#define UINT_C CONCAT3 (UINT, BITS, _C)
-#define FMT_UINT_T CONCAT (PRId, BITS)
-#define WITH_BITS(X) CONCAT3 (X, _u, BITS)
+#if !(defined(UINT_T) && defined(UINT_C) && defined(UINT_FMT_S) && \
+ defined(DECORATE_NAME))
+#ifdef __INTELLISENSE__
+#define UINT_T uint32_t
+#define UINT_C UINT32_C
+#define UINT_FMT_S PRIu32
+#define DECORATE_NAME(Name) Name##_u32
+#else
+#error All of UINT_T, UINT_C, UINT_FMT_S, UINT_FMT_ARG, and DECORATE_NAME must be defined before #including this file
+#endif
+#endif
+
+#define BITS (sizeof (UINT_T) * CHAR_BIT)
+
+#define ZERO UINT_C (0)
+
+// Default for UINT_FMT_ARG
+#ifndef UINT_FMT_ARG
+#define UINT_FMT_ARG(X) X
+#endif
+
+// Default comparison
+#ifndef UINT_LESSTHAN
+#define UINT_LESSTHAN(A, B) ((A) < (B))
+#endif
+#ifndef MC_UINT_MAX
+#define MC_UINT_MAX ~(UINT_C (0))
+#endif
+
+// Default addition
+#ifndef UINT_ADD
+#define UINT_ADD(A, B) ((A) + (B))
+#endif
+#ifndef UINT_SUB
+#define UINT_SUB(A, B) ((A) - (B))
+#endif
+
+// Default lshift (also handles negatives as right-shift)
+#ifndef UINT_LSHIFT
+static inline UINT_T
+DECORATE_NAME (_mc_default_lshift) (UINT_T lhs, int off)
+{
+ if (off < 0) {
+ return lhs >> -off;
+ } else {
+ return lhs << off;
+ }
+}
+#define UINT_LSHIFT DECORATE_NAME (_mc_default_lshift)
+#endif
+
+#ifndef UINT_BITOR
+#define UINT_BITOR(A, B) ((A) | (B))
+#endif
+
+static inline int
+DECORATE_NAME (_mc_compare) (UINT_T lhs, UINT_T rhs)
+{
+ if (UINT_LESSTHAN (lhs, rhs)) {
+ return -1;
+ } else if (UINT_LESSTHAN (rhs, lhs)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#define UINT_COMPARE DECORATE_NAME (_mc_compare)
// MinCoverGenerator models the MinCoverGenerator type added in
// SERVER-68600.
@@ -46,31 +107,31 @@ typedef struct {
size_t _sparsity;
// _maxlen is the maximum bit length of edges in the mincover.
size_t _maxlen;
-} WITH_BITS (MinCoverGenerator);
-
-static inline WITH_BITS (MinCoverGenerator) *
- WITH_BITS (MinCoverGenerator_new) (UINT_T rangeMin,
- UINT_T rangeMax,
- UINT_T max,
- size_t sparsity,
- mongocrypt_status_t *status)
+} DECORATE_NAME (MinCoverGenerator);
+
+static inline DECORATE_NAME (MinCoverGenerator) *
+ DECORATE_NAME (MinCoverGenerator_new) (UINT_T rangeMin,
+ UINT_T rangeMax,
+ UINT_T max,
+ size_t sparsity,
+ mongocrypt_status_t *status)
{
BSON_ASSERT_PARAM (status);
- if (rangeMin > rangeMax) {
- CLIENT_ERR ("Range min (%" FMT_UINT_T
- ") must be less than or equal to range max (%" FMT_UINT_T
+ if (UINT_COMPARE (rangeMin, rangeMax) > 0) {
+ CLIENT_ERR ("Range min (%" UINT_FMT_S
+ ") must be less than or equal to range max (%" UINT_FMT_S
") for range search",
- rangeMin,
- rangeMax);
+ UINT_FMT_ARG (rangeMin),
+ UINT_FMT_ARG (rangeMax));
return NULL;
}
- if (rangeMax > max) {
- CLIENT_ERR ("Range max (%" FMT_UINT_T
- ") must be less than or equal to max (%" FMT_UINT_T
+ if (UINT_COMPARE (rangeMax, max) > 0) {
+ CLIENT_ERR ("Range max (%" UINT_FMT_S
+ ") must be less than or equal to max (%" UINT_FMT_S
") for range search",
- rangeMax,
- max);
+ UINT_FMT_ARG (rangeMax),
+ UINT_FMT_ARG (max));
return NULL;
}
@@ -78,17 +139,18 @@ static inline WITH_BITS (MinCoverGenerator) *
CLIENT_ERR ("Sparsity must be > 0");
return NULL;
}
- WITH_BITS (MinCoverGenerator) *mcg =
- bson_malloc0 (sizeof (WITH_BITS (MinCoverGenerator)));
+ DECORATE_NAME (MinCoverGenerator) *mcg =
+ bson_malloc0 (sizeof (DECORATE_NAME (MinCoverGenerator)));
mcg->_rangeMin = rangeMin;
mcg->_rangeMax = rangeMax;
- mcg->_maxlen = (size_t) BITS - WITH_BITS (mc_count_leading_zeros) (max);
+ mcg->_maxlen = (size_t) BITS - DECORATE_NAME (mc_count_leading_zeros) (max);
mcg->_sparsity = sparsity;
return mcg;
}
static inline void
-WITH_BITS (MinCoverGenerator_destroy) (WITH_BITS (MinCoverGenerator) * mcg)
+DECORATE_NAME (MinCoverGenerator_destroy) (DECORATE_NAME (MinCoverGenerator) *
+ mcg)
{
bson_free (mcg);
}
@@ -96,9 +158,9 @@ WITH_BITS (MinCoverGenerator_destroy) (WITH_BITS (MinCoverGenerator) * mcg)
// applyMask applies a mask of 1 bits starting from the right.
// Bits 0 to bit-1 are replaced with 1. Other bits are left as-is.
static inline UINT_T
-WITH_BITS (applyMask) (UINT_T value, size_t maskedBits)
+DECORATE_NAME (applyMask) (UINT_T value, size_t maskedBits)
{
- const UINT_T ones = ~UINT_C (0);
+ const UINT_T ones = MC_UINT_MAX;
BSON_ASSERT (maskedBits <= (size_t) BITS);
BSON_ASSERT (maskedBits >= 0);
@@ -108,14 +170,13 @@ WITH_BITS (applyMask) (UINT_T value, size_t maskedBits)
}
const size_t shift = ((size_t) BITS - maskedBits);
- const UINT_T mask = ones >> shift;
- return value | mask;
+ const UINT_T mask = UINT_LSHIFT (ones, -(int) shift);
+ return UINT_BITOR (value, mask);
}
static inline bool
-WITH_BITS (MinCoverGenerator_isLevelStored) (WITH_BITS (MinCoverGenerator) *
- mcg,
- size_t maskedBits)
+DECORATE_NAME (MinCoverGenerator_isLevelStored) (
+ DECORATE_NAME (MinCoverGenerator) * mcg, size_t maskedBits)
{
BSON_ASSERT_PARAM (mcg);
size_t level = mcg->_maxlen - maskedBits;
@@ -123,9 +184,8 @@ WITH_BITS (MinCoverGenerator_isLevelStored) (WITH_BITS (MinCoverGenerator) *
}
char *
-WITH_BITS (MinCoverGenerator_toString) (WITH_BITS (MinCoverGenerator) * mcg,
- UINT_T start,
- size_t maskedBits)
+DECORATE_NAME (MinCoverGenerator_toString) (
+ DECORATE_NAME (MinCoverGenerator) * mcg, UINT_T start, size_t maskedBits)
{
BSON_ASSERT_PARAM (mcg);
BSON_ASSERT (maskedBits <= mcg->_maxlen);
@@ -136,33 +196,35 @@ WITH_BITS (MinCoverGenerator_toString) (WITH_BITS (MinCoverGenerator) * mcg,
return bson_strdup ("root");
}
- UINT_T shifted = start >> maskedBits;
- char *valueBin = WITH_BITS (mc_convert_to_bitstring) (shifted);
+ UINT_T shifted = UINT_LSHIFT (start, -(int) maskedBits);
+ mc_bitstring valueBin = DECORATE_NAME (mc_convert_to_bitstring) (shifted);
char *ret =
- bson_strndup (valueBin + ((size_t) BITS - mcg->_maxlen + maskedBits),
+ bson_strndup (valueBin.str + ((size_t) BITS - mcg->_maxlen + maskedBits),
mcg->_maxlen + maskedBits);
- bson_free (valueBin);
return ret;
}
static inline void
-WITH_BITS (MinCoverGenerator_minCoverRec) (WITH_BITS (MinCoverGenerator) * mcg,
- mc_array_t *c,
- UINT_T blockStart,
- size_t maskedBits)
+DECORATE_NAME (MinCoverGenerator_minCoverRec) (
+ DECORATE_NAME (MinCoverGenerator) * mcg,
+ mc_array_t *c,
+ UINT_T blockStart,
+ size_t maskedBits)
{
BSON_ASSERT_PARAM (mcg);
BSON_ASSERT_PARAM (c);
- const UINT_T blockEnd = WITH_BITS (applyMask) (blockStart, maskedBits);
+ const UINT_T blockEnd = DECORATE_NAME (applyMask) (blockStart, maskedBits);
- if (blockEnd < mcg->_rangeMin || blockStart > mcg->_rangeMax) {
+ if (UINT_COMPARE (blockEnd, mcg->_rangeMin) < 0 ||
+ UINT_COMPARE (blockStart, mcg->_rangeMax) > 0) {
return;
}
- if (blockStart >= mcg->_rangeMin && blockEnd <= mcg->_rangeMax &&
- WITH_BITS (MinCoverGenerator_isLevelStored) (mcg, maskedBits)) {
- char *edge =
- WITH_BITS (MinCoverGenerator_toString) (mcg, blockStart, maskedBits);
+ if (UINT_COMPARE (blockStart, mcg->_rangeMin) >= 0 &&
+ UINT_COMPARE (blockEnd, mcg->_rangeMax) <= 0 &&
+ DECORATE_NAME (MinCoverGenerator_isLevelStored) (mcg, maskedBits)) {
+ char *edge = DECORATE_NAME (MinCoverGenerator_toString) (
+ mcg, blockStart, maskedBits);
_mc_array_append_val (c, edge);
return;
}
@@ -170,18 +232,22 @@ WITH_BITS (MinCoverGenerator_minCoverRec) (WITH_BITS (MinCoverGenerator) * mcg,
BSON_ASSERT (maskedBits > 0);
const size_t newBits = maskedBits - 1u;
- WITH_BITS (MinCoverGenerator_minCoverRec) (mcg, c, blockStart, newBits);
- WITH_BITS (MinCoverGenerator_minCoverRec)
- (mcg, c, blockStart | UINT_C (1) << newBits, newBits);
+ DECORATE_NAME (MinCoverGenerator_minCoverRec) (mcg, c, blockStart, newBits);
+ DECORATE_NAME (MinCoverGenerator_minCoverRec)
+ (mcg,
+ c,
+ UINT_BITOR (blockStart, UINT_LSHIFT (UINT_C (1), (int) newBits)),
+ newBits);
}
static inline mc_mincover_t *
-WITH_BITS (MinCoverGenerator_minCover) (WITH_BITS (MinCoverGenerator) * mcg)
+DECORATE_NAME (MinCoverGenerator_minCover) (DECORATE_NAME (MinCoverGenerator) *
+ mcg)
{
BSON_ASSERT_PARAM (mcg);
mc_mincover_t *mc = mc_mincover_new ();
- WITH_BITS (MinCoverGenerator_minCoverRec)
- (mcg, &mc->mincover, 0, mcg->_maxlen);
+ DECORATE_NAME (MinCoverGenerator_minCoverRec)
+ (mcg, &mc->mincover, ZERO, mcg->_maxlen);
return mc;
}
@@ -190,43 +256,53 @@ WITH_BITS (MinCoverGenerator_minCover) (WITH_BITS (MinCoverGenerator) * mcg)
// lowerBound, min, upperBound, and max are expected to come from the result
// of mc_getTypeInfo.
static bool
-WITH_BITS (adjustBounds) (UINT_T *lowerBound,
- bool includeLowerBound,
- UINT_T min,
- UINT_T *upperBound,
- bool includeUpperBound,
- UINT_T max,
- mongocrypt_status_t *status)
+DECORATE_NAME (adjustBounds) (UINT_T *lowerBound,
+ bool includeLowerBound,
+ UINT_T min,
+ UINT_T *upperBound,
+ bool includeUpperBound,
+ UINT_T max,
+ mongocrypt_status_t *status)
{
BSON_ASSERT_PARAM (lowerBound);
BSON_ASSERT_PARAM (upperBound);
if (!includeLowerBound) {
- if (*lowerBound >= max) {
- CLIENT_ERR ("Lower bound (%" FMT_UINT_T
- ") must be less than the range maximum (%" FMT_UINT_T
+ if (UINT_COMPARE (*lowerBound, max) >= 0) {
+ CLIENT_ERR ("Lower bound (%" UINT_FMT_S
+ ") must be less than the range maximum (%" UINT_FMT_S
") if lower bound is excluded from range.",
- *lowerBound,
- max);
+ UINT_FMT_ARG (*lowerBound),
+ UINT_FMT_ARG (max));
return false;
}
- *lowerBound += 1u;
+ *lowerBound = UINT_ADD (*lowerBound, UINT_C (1));
}
if (!includeUpperBound) {
- if (*upperBound <= min) {
- CLIENT_ERR ("Upper bound (%" FMT_UINT_T
- ") must be greater than the range minimum (%" FMT_UINT_T
+ if (UINT_COMPARE (*upperBound, min) <= 0) {
+ CLIENT_ERR ("Upper bound (%" UINT_FMT_S
+ ") must be greater than the range minimum (%" UINT_FMT_S
") if upper bound is excluded from range.",
- *upperBound,
- max);
+ UINT_FMT_ARG (*upperBound),
+ UINT_FMT_ARG (min));
return false;
}
- *upperBound -= 1u;
+ *upperBound = UINT_SUB (*upperBound, UINT_C (1));
}
return true;
}
#undef UINT_T
#undef UINT_C
-#undef FMT_UINT_T
-#undef WITH_BITS
+#undef UINT_FMT_S
+#undef UINT_FMT_ARG
+#undef DECORATE_NAME
+#undef BITS
+#undef UINT_COMPARE
+#undef UINT_ADD
+#undef UINT_SUB
+#undef UINT_LSHIFT
+#undef UINT_BITOR
+#undef MC_UINT_MAX
+#undef ZERO
+#undef UINT_LESSTHAN
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-mincover-private.h b/src/third_party/libmongocrypt/dist/src/mc-range-mincover-private.h
index 78d6bafdf60..1a9ec6daf8e 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-mincover-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-mincover-private.h
@@ -21,6 +21,7 @@
#include <stdint.h>
#include "mc-optional-private.h"
#include "mongocrypt-status-private.h"
+#include "mc-dec128.h"
// mc_mincover_t represents the results of the mincover algorithm.
typedef struct _mc_mincover_t mc_mincover_t;
@@ -88,4 +89,22 @@ mc_getMincoverDouble (mc_getMincoverDouble_args_t args,
mongocrypt_status_t *status)
MONGOCRYPT_WARN_UNUSED_RESULT;
+
+typedef struct {
+ mc_dec128 lowerBound;
+ bool includeLowerBound;
+ mc_dec128 upperBound;
+ bool includeUpperBound;
+ size_t sparsity;
+ mc_optional_dec128_t min, max;
+ mc_optional_uint32_t precision;
+} mc_getMincoverDecimal128_args_t;
+
+// mc_getMincoverDecimal128 implements the Mincover Generation algorithm
+// described in SERVER-68600 for Decimal128 (as mc_dec128).
+mc_mincover_t *
+mc_getMincoverDecimal128 (mc_getMincoverDecimal128_args_t args,
+ mongocrypt_status_t *status)
+ MONGOCRYPT_WARN_UNUSED_RESULT;
+
#endif /* MC_RANGE_MINCOVER_PRIVATE_H */
diff --git a/src/third_party/libmongocrypt/dist/src/mc-range-mincover.c b/src/third_party/libmongocrypt/dist/src/mc-range-mincover.c
index a8e1de4458f..d5c9dd17232 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-range-mincover.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-range-mincover.c
@@ -68,49 +68,73 @@ mc_mincover_destroy (mc_mincover_t *mincover)
bson_free (mincover);
}
-#define BITS 32
+#define UINT_T uint32_t
+#define UINT_C UINT32_C
+#define UINT_FMT_S PRIu32
+#define DECORATE_NAME(N) N##_u32
#include "mc-range-mincover-generator.template.h"
-#undef BITS
+
+#define UINT_T uint64_t
+#define UINT_C UINT64_C
+#define UINT_FMT_S PRIu64
+#define DECORATE_NAME(N) N##_u64
+#include "mc-range-mincover-generator.template.h"
+
+#define UINT_T mlib_int128
+#define UINT_C MLIB_INT128
+#define UINT_FMT_S "s"
+#define UINT_FMT_ARG(X) (mlib_int128_format (X).str)
+#define DECORATE_NAME(N) N##_u128
+#define UINT_LESSTHAN(L, R) (mlib_int128_ucmp (L, R) < 0)
+#define UINT_ADD mlib_int128_add
+#define UINT_SUB mlib_int128_sub
+#define UINT_LSHIFT mlib_int128_lshift
+#define MC_UINT_MAX MLIB_INT128_UMAX
+#define UINT_BITOR mlib_int128_bitor
+#include "mc-range-mincover-generator.template.h"
+
// Check bounds and return an error message including the original inputs.
-#define CHECK_BOUNDS(args, FMT) \
+#define IDENTITY(X) X
+#define LESSTHAN(L, R) ((L) < (R))
+#define CHECK_BOUNDS(args, FMT, FormatArg, LessThan) \
if (1) { \
if ((args).min.set) { \
- if ((args).upperBound < (args).min.value) { \
+ if (LessThan ((args).upperBound, (args).min.value)) { \
CLIENT_ERR ( \
"Upper bound (%" FMT \
") must be greater than or equal to the range minimum (%" FMT \
")", \
- (args).upperBound, \
- (args).min.value); \
+ FormatArg ((args).upperBound), \
+ FormatArg ((args).min.value)); \
return false; \
} \
if (!(args).includeUpperBound && \
- (args).upperBound <= (args).min.value) { \
+ !LessThan ((args.min.value), (args.upperBound))) { \
CLIENT_ERR ("Upper bound (%" FMT \
") must be greater than the range minimum (%" FMT \
") if upper bound is excluded from range", \
- (args).upperBound, \
- (args).min.value); \
+ FormatArg ((args).upperBound), \
+ FormatArg ((args).min.value)); \
return false; \
} \
} \
if ((args).max.set) { \
- if ((args).lowerBound > (args).max.value) { \
+ if (LessThan ((args).max.value, (args).lowerBound)) { \
CLIENT_ERR ( \
"Lower bound (%" FMT \
") must be less than or equal to the range maximum (%" FMT ")", \
- (args).lowerBound, \
- (args).max.value); \
+ FormatArg ((args).lowerBound), \
+ FormatArg ((args).max.value)); \
return false; \
} \
if (!(args).includeLowerBound && \
- (args).lowerBound >= (args).max.value) { \
+ !LessThan ((args).lowerBound, (args).max.value)) { \
CLIENT_ERR ("Lower bound (%" FMT \
") must be less than the range maximum (%" FMT \
") if lower bound is excluded from range", \
- (args).lowerBound, \
- (args).max.value); \
+ FormatArg ((args).lowerBound), \
+ FormatArg ((args).max.value)); \
return false; \
} \
} \
@@ -122,7 +146,7 @@ mc_getMincoverInt32 (mc_getMincoverInt32_args_t args,
mongocrypt_status_t *status)
{
BSON_ASSERT_PARAM (status);
- CHECK_BOUNDS (args, PRId32);
+ CHECK_BOUNDS (args, PRId32, IDENTITY, LESSTHAN);
mc_OSTType_Int32 a, b;
if (!mc_getTypeInfo32 ((mc_getTypeInfo32_args_t){.min = args.min,
.max = args.max,
@@ -162,16 +186,12 @@ mc_getMincoverInt32 (mc_getMincoverInt32_args_t args,
return mc;
}
-#define BITS 64
-#include "mc-range-mincover-generator.template.h"
-#undef BITS
-
mc_mincover_t *
mc_getMincoverInt64 (mc_getMincoverInt64_args_t args,
mongocrypt_status_t *status)
{
BSON_ASSERT_PARAM (status);
- CHECK_BOUNDS (args, PRId64);
+ CHECK_BOUNDS (args, PRId64, IDENTITY, LESSTHAN);
mc_OSTType_Int64 a, b;
if (!mc_getTypeInfo64 ((mc_getTypeInfo64_args_t){.min = args.min,
.max = args.max,
@@ -218,7 +238,7 @@ mc_getMincoverDouble (mc_getMincoverDouble_args_t args,
mongocrypt_status_t *status)
{
BSON_ASSERT_PARAM (status);
- CHECK_BOUNDS (args, "g");
+ CHECK_BOUNDS (args, "g", IDENTITY, LESSTHAN);
mc_OSTType_Double a, b;
if (!mc_getTypeInfoDouble (
@@ -262,3 +282,54 @@ mc_getMincoverDouble (mc_getMincoverDouble_args_t args,
MinCoverGenerator_destroy_u64 (mcg);
return mc;
}
+
+mc_mincover_t *
+mc_getMincoverDecimal128 (mc_getMincoverDecimal128_args_t args,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (status);
+#define ToString(Dec) (mc_dec128_to_string (Dec).str)
+ CHECK_BOUNDS (args, "s", ToString, mc_dec128_less);
+
+ mc_OSTType_Decimal128 a, b;
+ if (!mc_getTypeInfoDecimal128 (
+ (mc_getTypeInfoDecimal128_args_t){.value = args.lowerBound,
+ .min = args.min,
+ .max = args.max,
+ .precision = args.precision},
+ &a,
+ status)) {
+ return NULL;
+ }
+ if (!mc_getTypeInfoDecimal128 (
+ (mc_getTypeInfoDecimal128_args_t){.value = args.upperBound,
+ .min = args.min,
+ .max = args.max,
+ .precision = args.precision},
+ &b,
+ status)) {
+ return NULL;
+ }
+
+ BSON_ASSERT (mlib_int128_eq (a.min, b.min));
+ BSON_ASSERT (mlib_int128_eq (a.max, b.max));
+
+ if (!adjustBounds_u128 (&a.value,
+ args.includeLowerBound,
+ a.min,
+ &b.value,
+ args.includeUpperBound,
+ b.max,
+ status)) {
+ return NULL;
+ }
+
+ MinCoverGenerator_u128 *mcg = MinCoverGenerator_new_u128 (
+ a.value, b.value, a.max, args.sparsity, status);
+ if (!mcg) {
+ return NULL;
+ }
+ mc_mincover_t *mc = MinCoverGenerator_minCover_u128 (mcg);
+ MinCoverGenerator_destroy_u128 (mcg);
+ return mc;
+}
diff --git a/src/third_party/libmongocrypt/dist/src/mc-rangeopts.c b/src/third_party/libmongocrypt/dist/src/mc-rangeopts.c
index 3bacc15795a..3b6a8d85a6b 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-rangeopts.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-rangeopts.c
@@ -282,6 +282,13 @@ mc_RangeOpts_appendMin (const mc_RangeOpts_t *ro,
CLIENT_ERR ("failed to append BSON");
return false;
}
+ } else if (valueType == BSON_TYPE_DECIMAL128) {
+ const bson_decimal128_t min =
+ mc_dec128_to_bson_decimal128 (MC_DEC128_LARGEST_NEGATIVE);
+ if (!BSON_APPEND_DECIMAL128 (out, fieldName, &min)) {
+ CLIENT_ERR ("failed to append BSON");
+ return false;
+ }
} else {
CLIENT_ERR ("unsupported BSON type: %s for range",
mc_bson_type_to_string (valueType));
@@ -337,6 +344,13 @@ mc_RangeOpts_appendMax (const mc_RangeOpts_t *ro,
CLIENT_ERR ("failed to append BSON");
return false;
}
+ } else if (valueType == BSON_TYPE_DECIMAL128) {
+ const bson_decimal128_t max =
+ mc_dec128_to_bson_decimal128 (MC_DEC128_LARGEST_POSITIVE);
+ if (!BSON_APPEND_DECIMAL128 (out, fieldName, &max)) {
+ CLIENT_ERR ("failed to append BSON");
+ return false;
+ }
} else {
CLIENT_ERR ("unsupported BSON type: %s for range",
mc_bson_type_to_string (valueType));
diff --git a/src/third_party/libmongocrypt/dist/src/mc-reader.c b/src/third_party/libmongocrypt/dist/src/mc-reader.c
index 8b87b815fae..a5730bd744d 100644
--- a/src/third_party/libmongocrypt/dist/src/mc-reader.c
+++ b/src/third_party/libmongocrypt/dist/src/mc-reader.c
@@ -185,7 +185,8 @@ mc_reader_read_buffer (mc_reader_t *reader,
buf, ptr, (size_t) length)) {
CLIENT_ERR ("%s failed to copy "
"data of length %" PRIu64,
- reader->parser_name);
+ reader->parser_name,
+ length);
return false;
}
diff --git a/src/third_party/libmongocrypt/dist/src/mc-writer-private.h b/src/third_party/libmongocrypt/dist/src/mc-writer-private.h
new file mode 100644
index 00000000000..96c132d354a
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mc-writer-private.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2022-present MongoDB, Inc.
+ *
+ * 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.
+ */
+
+#ifndef MONGOCRYPT_WRITER_PRIVATE_H
+#define MONGOCRYPT_WRITER_PRIVATE_H
+
+#include "mongocrypt-buffer-private.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * A non-owning forward-only cursor api to write to a buffer.
+ *
+ * Tracks length of buffer and current position of buffer. parser_name is
+ * typically __FUNCTION__ to provide useful error messages automatically.
+ *
+ * All numbers are written as little endian.
+ */
+
+struct _mc_writer_t {
+ uint8_t *ptr;
+ uint64_t pos;
+ uint64_t len;
+
+ const char *parser_name;
+};
+
+typedef struct _mc_writer_t mc_writer_t;
+
+void
+mc_writer_init (mc_writer_t *writer,
+ uint8_t *ptr,
+ uint64_t len,
+ const char *parser_name);
+
+void
+mc_writer_init_from_buffer (mc_writer_t *writer,
+ _mongocrypt_buffer_t *buf,
+ const char *parser_name);
+
+mc_writer_t *
+mc_writer_new (uint8_t *ptr, uint64_t len, const char *parser_name);
+
+void
+mc_writer_destroy (mc_writer_t *writer);
+
+bool
+mc_writer_write_u8 (mc_writer_t *writer,
+ const uint8_t value,
+ mongocrypt_status_t *status);
+
+bool
+mc_writer_write_u32 (mc_writer_t *writer,
+ const uint32_t value,
+ mongocrypt_status_t *status);
+
+bool
+mc_writer_write_u64 (mc_writer_t *writer,
+ const uint64_t value,
+ mongocrypt_status_t *status);
+
+bool
+mc_writer_write_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ uint64_t length,
+ mongocrypt_status_t *status);
+
+
+bool
+mc_writer_write_uuid_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status);
+
+bool
+mc_writer_write_prfblock_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status);
+
+#endif /* MONGOCRYPT_READER_PRIVATE_H */
diff --git a/src/third_party/libmongocrypt/dist/src/mc-writer.c b/src/third_party/libmongocrypt/dist/src/mc-writer.c
new file mode 100644
index 00000000000..55c208a2020
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mc-writer.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2022-present MongoDB, Inc.
+ *
+ * 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 "mongocrypt-private.h"
+
+#include "mc-writer-private.h"
+
+#define CHECK_AND_RETURN(x) \
+ if (!(x)) { \
+ return false; \
+ }
+
+#define CHECK_REMAINING_BUFFER_AND_RET(write_size) \
+ if ((write_size) > writer->len - writer->pos) { \
+ CLIENT_ERR ("%s expected at most %" PRIu64 \
+ " bytes, got: %" PRIu64, \
+ writer->parser_name, \
+ (writer->len - writer->pos), \
+ (uint64_t) (write_size)); \
+ return false; \
+ }
+
+void
+mc_writer_init (mc_writer_t *writer,
+ uint8_t *ptr,
+ uint64_t len,
+ const char *parser_name)
+{
+ BSON_ASSERT_PARAM (writer);
+ BSON_ASSERT_PARAM (ptr);
+ BSON_ASSERT_PARAM (parser_name);
+
+ *writer = (mc_writer_t){
+ .pos = 0u, .ptr = ptr, .len = len, .parser_name = parser_name};
+}
+
+void
+mc_writer_init_from_buffer (mc_writer_t *writer,
+ _mongocrypt_buffer_t *buf,
+ const char *parser_name)
+{
+ BSON_ASSERT_PARAM (writer);
+ BSON_ASSERT_PARAM (buf);
+ BSON_ASSERT_PARAM (parser_name);
+
+ mc_writer_init (writer, buf->data, buf->len, parser_name);
+}
+
+mc_writer_t *
+mc_writer_new (uint8_t *ptr, uint64_t len, const char *parser_name)
+{
+ BSON_ASSERT_PARAM (ptr);
+ BSON_ASSERT_PARAM (parser_name);
+
+ mc_writer_t *writer = bson_malloc (sizeof (mc_writer_t));
+ mc_writer_init (writer, ptr, len, parser_name);
+ return writer;
+}
+
+void
+mc_writer_destroy (mc_writer_t *writer)
+{
+ bson_free (writer);
+}
+
+bool
+mc_writer_write_u8 (mc_writer_t *writer,
+ const uint8_t value,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (writer);
+ CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint8_t));
+ memcpy (writer->ptr + writer->pos, &value, sizeof (uint8_t));
+
+ writer->pos += sizeof (uint8_t);
+ return true;
+}
+
+bool
+mc_writer_write_u32 (mc_writer_t *writer,
+ const uint32_t value,
+ mongocrypt_status_t *status)
+{
+ CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint32_t));
+
+ uint32_t temp = BSON_UINT32_TO_LE (value);
+ memcpy (writer->ptr + writer->pos, &temp, sizeof (uint32_t));
+ writer->pos += sizeof (uint32_t);
+
+ return true;
+}
+
+bool
+mc_writer_write_u64 (mc_writer_t *writer,
+ const uint64_t value,
+ mongocrypt_status_t *status)
+{
+ CHECK_REMAINING_BUFFER_AND_RET (sizeof (uint64_t));
+
+ uint64_t temp = BSON_UINT64_TO_LE (value);
+ memcpy (writer->ptr + writer->pos, &temp, sizeof (uint64_t));
+ writer->pos += sizeof (uint64_t);
+
+ return true;
+}
+
+bool
+mc_writer_write_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ uint64_t length,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (writer);
+ BSON_ASSERT_PARAM (buf);
+
+ if (length > buf->len) {
+ CLIENT_ERR ("%s cannot write %" PRIu64
+ " bytes from buffer with length %" PRIu32,
+ writer->parser_name,
+ length,
+ buf->len);
+
+ return false;
+ }
+
+ CHECK_REMAINING_BUFFER_AND_RET (length);
+
+ if (length > SIZE_MAX) {
+ CLIENT_ERR ("%s failed to copy "
+ "data of length %" PRIu64,
+ writer->parser_name,
+ length);
+ return false;
+ }
+
+ memcpy (writer->ptr + writer->pos, buf->data, (size_t) length);
+ writer->pos += length;
+
+ return true;
+}
+
+bool
+mc_writer_write_uuid_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (writer);
+ BSON_ASSERT_PARAM (buf);
+
+ CHECK_AND_RETURN (mc_writer_write_buffer (writer, buf, UUID_LEN, status));
+ return true;
+}
+
+bool
+mc_writer_write_prfblock_buffer (mc_writer_t *writer,
+ const _mongocrypt_buffer_t *buf,
+ mongocrypt_status_t *status)
+{
+ BSON_ASSERT_PARAM (writer);
+ BSON_ASSERT_PARAM (buf);
+
+ CHECK_AND_RETURN (mc_writer_write_buffer (writer, buf, PRF_LEN, status));
+ return true;
+}
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/check.hpp b/src/third_party/libmongocrypt/dist/src/mlib/check.hpp
new file mode 100644
index 00000000000..18642b2f624
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mlib/check.hpp
@@ -0,0 +1,89 @@
+#ifndef MLIB_CHECK_HPP_INCLUDED
+#define MLIB_CHECK_HPP_INCLUDED
+
+#include <iostream>
+#include <cstdio>
+#include <string>
+
+namespace mlib
+{
+namespace detail
+{
+struct check_info {
+ const char *filename;
+ int line;
+ const char *expr;
+};
+
+struct nil {
+};
+
+template <typename Left> struct bound_lhs {
+ check_info info;
+ Left value;
+
+#define DEFOP(Oper) \
+ template <typename Rhs> nil operator Oper (Rhs rhs) const noexcept \
+ { \
+ if (value Oper rhs) { \
+ return {}; \
+ } \
+ std::fprintf (stderr, \
+ "%s:%d: CHECK( %s ) failed!\n", \
+ info.filename, \
+ info.line, \
+ info.expr); \
+ std::cerr << "Expanded expression: " << value << " " #Oper " " << rhs \
+ << '\n'; \
+ std::exit (2); \
+ }
+ DEFOP (==)
+ DEFOP (!=)
+ DEFOP (<)
+ DEFOP (<=)
+ DEFOP (>)
+ DEFOP (>=)
+#undef DEFOP
+};
+
+struct check_magic {
+ check_info info;
+
+ template <typename Oper>
+ bound_lhs<Oper>
+ operator->*(Oper op)
+ {
+ return bound_lhs<Oper>{info, op};
+ }
+};
+
+struct check_consume {
+ void
+ operator= (nil)
+ {
+ }
+
+ void
+ operator= (bound_lhs<bool> const &l)
+ {
+ // Invoke the test for truthiness:
+ (void) (l == true);
+ }
+};
+
+/**
+ * @brief Create an assertion that prints the expanded expression upon failure.
+ *
+ * Only supports simple comparison binary expressions, and plain boolean
+ * expressions
+ */
+#define MLIB_CHECK(Cond) \
+ ::mlib::detail::check_consume{} = \
+ ::mlib::detail::check_magic{ \
+ ::mlib::detail::check_info{__FILE__, __LINE__, #Cond}} \
+ ->*Cond
+
+} // namespace detail
+} // namespace mlib
+
+#endif // MLIB_CHECK_HPP_INCLUDED
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/endian.h b/src/third_party/libmongocrypt/dist/src/mlib/endian.h
new file mode 100644
index 00000000000..e44080dde1c
--- /dev/null
+++ b/src/third_party/libmongocrypt/dist/src/mlib/endian.h
@@ -0,0 +1,42 @@
+#ifndef MLIB_ENDIAN_H_INCLUDED
+#define MLIB_ENDIAN_H_INCLUDED
+
+#ifdef __has_include
+// Some platforms require including other headers that will define the necessary
+// macros
+#if __has_include(<endian.h>)
+// This may recursively include our own file in a pathological case, but that
+// won't cause an issue. The default will include the system's version instead:
+#include <endian.h>
+#endif
+#if __has_include(<sys/param.h>)
+#include <sys/param.h>
+#endif
+#endif
+
+#include "./macros.h"
+
+enum mlib_endian_kind {
+#ifdef _MSC_VER // MSVC only targets little-endian arches at the moment
+ MLIB_ENDIAN_LITTLE = 1234,
+ MLIB_ENDIAN_BIG = 4321,
+ MLIB_ENDIAN_NATIVE = MLIB_ENDIAN_LITTLE,
+#elif defined(__BYTE_ORDER__) // Commonly built-in defined in newer compilers
+ MLIB_ENDIAN_LITTLE = __ORDER_LITTLE_ENDIAN__,
+ MLIB_ENDIAN_BIG = __ORDER_BIG_ENDIAN__,
+ MLIB_ENDIAN_NATIVE = __BYTE_ORDER__,
+#elif defined(__BYTE_ORDER) // Common in <sys/param.h> or <endian.h>
+ MLIB_ENDIAN_LITTLE = __LITTLE_ENDIAN,
+ MLIB_ENDIAN_BIG = __BIG_ENDIAN,
+ MLIB_ENDIAN_NATIVE = __BYTE_ORDER,
+#else
+#error This compiler does not define an endianness macro.
+#endif
+};
+
+enum {
+ MLIB_IS_LITTLE_ENDIAN = MLIB_ENDIAN_NATIVE == MLIB_ENDIAN_LITTLE,
+ MLIB_IS_BIG_ENDIAN = MLIB_ENDIAN_NATIVE == MLIB_ENDIAN_BIG,
+};
+
+#endif // MLIB_ENDIAN_H_INCLUDED
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/int128.h b/src/third_party/libmongocrypt/dist/src/mlib/int128.h
index dfb02a02668..149411710fe 100644
--- a/src/third_party/libmongocrypt/dist/src/mlib/int128.h
+++ b/src/third_party/libmongocrypt/dist/src/mlib/int128.h
@@ -131,7 +131,7 @@ mlib_int128_add (mlib_int128 left, mlib_int128 right)
{
uint64_t losum = left.r.lo + right.r.lo;
// Overflow check
- int carry = (losum < left.r.lo || losum < right.r.lo);
+ unsigned carry = (losum < left.r.lo || losum < right.r.lo);
uint64_t hisum = left.r.hi + right.r.hi + carry;
return MLIB_INIT (mlib_int128) MLIB_INT128_FROM_PARTS (losum, hisum);
}
@@ -156,7 +156,7 @@ mlib_int128_negate (mlib_int128 v)
static mlib_constexpr_fn mlib_int128
mlib_int128_sub (mlib_int128 from, mlib_int128 less)
{
- int borrow = from.r.lo < less.r.lo;
+ unsigned borrow = from.r.lo < less.r.lo;
uint64_t low = from.r.lo - less.r.lo;
uint64_t high = from.r.hi - less.r.hi;
high -= borrow;
@@ -338,7 +338,7 @@ _mlibKnuth431D (uint32_t *const u,
u[i + j] = (u32) (t);
k = t >> 32;
}
- u[j + n] += (int32_t) k;
+ u[j + n] += (u32) k;
}
// D7:
@@ -516,9 +516,9 @@ mlib_int128_divmod (mlib_int128 numer, mlib_int128 denom)
(uint32_t) (denom.r.hi >> (32 - d)),
};
if (d != 0) {
- u[2] |= numer.r.lo >> (64 - d);
- u[4] |= numer.r.hi >> (64 - d);
- v[2] |= denom.r.lo >> (64 - d);
+ u[2] |= (uint32_t) (numer.r.lo >> (64 - d));
+ u[4] |= (uint32_t) (numer.r.hi >> (64 - d));
+ v[2] |= (uint32_t) (denom.r.lo >> (64 - d));
};
uint32_t q[2] = {0};
@@ -561,7 +561,7 @@ mlib_int128_mod (mlib_int128 numer, mlib_int128 denom)
* @brief Get the nth power of ten as a 128-bit number
*/
static mlib_constexpr_fn mlib_int128
-mlib_int128_pow10 (long nth)
+mlib_int128_pow10 (uint8_t nth)
{
mlib_int128 r = MLIB_INT128 (1);
while (nth-- > 0) {
@@ -574,9 +574,9 @@ mlib_int128_pow10 (long nth)
* @brief Get the Nth power of two as a 128-bit number
*/
static mlib_constexpr_fn mlib_int128
-mlib_int128_pow2 (long nth)
+mlib_int128_pow2 (uint8_t nth)
{
- return mlib_int128_lshift (MLIB_INT128 (1), nth);
+ return mlib_int128_lshift (MLIB_INT128 (1), (int) nth);
}
/**
@@ -612,7 +612,8 @@ mlib_int128_from_string (const char *s, const char **end)
continue;
}
if (c >= 'a') {
- c -= 'a' - 'A'; // Uppercase (if a letter, otherwise some other punct)
+ // Uppercase (if a letter, otherwise some other punct):
+ c = (char) (c - ('a' - 'A'));
}
int digit = c - '0';
if (c >= 'A') {
@@ -655,7 +656,7 @@ typedef struct {
static mlib_constexpr_fn mlib_int128_charbuf
mlib_int128_format (mlib_int128 i)
{
- mlib_int128_charbuf into = {0};
+ mlib_int128_charbuf into = {{0}};
char *out = into.str + (sizeof into) - 1;
int len = 0;
if (mlib_int128_eq (i, MLIB_INT128 (0))) {
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/int128.test.cpp b/src/third_party/libmongocrypt/dist/src/mlib/int128.test.cpp
index e9e24788844..a1c1e4b5542 100644
--- a/src/third_party/libmongocrypt/dist/src/mlib/int128.test.cpp
+++ b/src/third_party/libmongocrypt/dist/src/mlib/int128.test.cpp
@@ -1,4 +1,8 @@
#include "./int128.h"
+#include "./endian.h"
+
+#include "./check.hpp"
+#define CHECK MLIB_CHECK
#include <iostream>
#include <random>
@@ -155,73 +159,6 @@ operator<< (std::ostream &out, const mlib_int128 &v)
return out;
}
-struct check_info {
- const char *filename;
- int line;
- const char *expr;
-};
-
-struct nil {
-};
-
-template <typename Left> struct bound_lhs {
- check_info info;
- Left value;
-
-#define DEFOP(Oper) \
- template <typename Rhs> nil operator Oper (Rhs rhs) const noexcept \
- { \
- if (value Oper rhs) { \
- return {}; \
- } \
- fprintf (stderr, \
- "%s:%d: CHECK( %s ) failed!\n", \
- info.filename, \
- info.line, \
- info.expr); \
- fprintf (stderr, "Expanded expression: "); \
- std::cerr << value << " " #Oper " " << rhs << '\n'; \
- std::exit (1); \
- return {}; \
- }
- DEFOP (==)
- DEFOP (!=)
- DEFOP (<)
- DEFOP (<=)
- DEFOP (>)
- DEFOP (>=)
-#undef DEFOP
-};
-
-struct check_magic {
- check_info info;
-
- template <typename Oper>
- bound_lhs<Oper>
- operator->*(Oper op)
- {
- return bound_lhs<Oper>{info, op};
- }
-};
-
-struct check_consume {
- void
- operator= (nil)
- {
- }
-
- void
- operator= (bound_lhs<bool> const &l)
- {
- // Invoke the test for truthiness:
- (void) (l == true);
- }
-};
-
-#undef CHECK
-#define CHECK(Cond) \
- check_consume{} = check_magic{check_info{__FILE__, __LINE__, #Cond}}->*Cond
-
#ifndef BROKEN_CONSTEXPR
static_assert (mlib_int128 (MLIB_INT128_UMAX) ==
340282366920938463463374607431768211455_i128,
@@ -239,6 +176,46 @@ static_assert (mlib_int128_negate (9223372036854775809_i128) <
"fail");
#endif
+#ifdef __SIZEOF_INT128__
+// mlib_int128_to_native converts mlib_int128 to native __uint128_t.
+// Endian-ness is accounted for.
+static __uint128_t
+mlib_int128_to_native (mlib_int128 in)
+{
+ __uint128_t out;
+ uint8_t *out_u8 = (uint8_t *) &out;
+ if (MLIB_IS_BIG_ENDIAN) {
+ // Copy hi, then lo.
+ memcpy (out_u8, &in.r.hi, sizeof (in.r.hi));
+ memcpy (out_u8 + sizeof (in.r.hi), &in.r.lo, sizeof (in.r.lo));
+ } else {
+ // Copy lo, then hi.
+ memcpy (out_u8, &in.r.lo, sizeof (in.r.lo));
+ memcpy (out_u8 + sizeof (in.r.lo), &in.r.hi, sizeof (in.r.hi));
+ }
+ return out;
+}
+
+// native_to_mlib_int128 converts native __uint128_t to mlib_int128.
+// Endian-ness is accounted for.
+static mlib_int128
+native_to_mlib_int128 (__uint128_t in)
+{
+ mlib_int128 out;
+ uint8_t *in_u8 = (uint8_t *) &in;
+ if (MLIB_IS_BIG_ENDIAN) {
+ // Copy hi, then lo.
+ memcpy (&out.r.hi, in_u8, sizeof (out.r.hi));
+ memcpy (&out.r.lo, in_u8 + sizeof (out.r.hi), sizeof (out.r.lo));
+ } else {
+ // Copy lo, then hi.
+ memcpy (&out.r.lo, in_u8, sizeof (out.r.lo));
+ memcpy (&out.r.hi, in_u8 + sizeof (out.r.lo), sizeof (out.r.hi));
+ }
+ return out;
+}
+#endif // __SIZEOF_INT128__
+
static mlib_int128_divmod_result
div_check (mlib_int128 num, mlib_int128 den)
{
@@ -246,15 +223,23 @@ div_check (mlib_int128 num, mlib_int128 den)
mlib_int128_divmod_result res = mlib_int128_divmod (num, den);
#ifdef __SIZEOF_INT128__
// When we have an existing i128 impl, test against that:
- __uint128_t num1;
- __uint128_t den1;
- memcpy (&num1, &num.r, sizeof num);
- memcpy (&den1, &den.r, sizeof den);
+ __uint128_t num1 = mlib_int128_to_native (num);
+ __uint128_t den1 = mlib_int128_to_native (den);
__uint128_t q = num1 / den1;
__uint128_t r = num1 % den1;
mlib_int128_divmod_result expect;
- memcpy (&expect.quotient.r, &q, sizeof q);
- memcpy (&expect.remainder.r, &r, sizeof r);
+ expect.quotient = native_to_mlib_int128 (q);
+ expect.remainder = native_to_mlib_int128 (r);
+ if (!mlib_int128_eq (expect.quotient, res.quotient) ||
+ !mlib_int128_eq (expect.remainder, res.remainder)) {
+ std::cout << "unexpected result in division"
+ << " num=" << mlib_int128_format (num).str
+ << " den=" << mlib_int128_format (den).str
+ << " expect.quotient="
+ << mlib_int128_format (expect.quotient).str
+ << " expect.remainder="
+ << mlib_int128_format (expect.remainder).str << std::endl;
+ }
CHECK (expect.quotient == res.quotient);
CHECK (expect.remainder == res.remainder);
#endif
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/macros.h b/src/third_party/libmongocrypt/dist/src/mlib/macros.h
index f586597b48a..14311622505 100644
--- a/src/third_party/libmongocrypt/dist/src/mlib/macros.h
+++ b/src/third_party/libmongocrypt/dist/src/mlib/macros.h
@@ -43,4 +43,11 @@
*/
#define mlib_constexpr_fn _mlibConstexprFn
+#ifdef __GNUC__
+#define MLIB_ANNOTATE_PRINTF(FStringArgAt, VarArgsStartAt) \
+ __attribute__ ((format (__printf__, FStringArgAt, VarArgsStartAt)))
+#else
+#define MLIB_ANNOTATE_PRINTF(FStringArgAt, VarArgsStartAt) /* no-op */
+#endif
+
#endif // MLIB_MACROS_H_INCLUDED
diff --git a/src/third_party/libmongocrypt/dist/src/mlib/str.h b/src/third_party/libmongocrypt/dist/src/mlib/str.h
index 3c36b61fe89..18f9ee9d339 100644
--- a/src/third_party/libmongocrypt/dist/src/mlib/str.h
+++ b/src/third_party/libmongocrypt/dist/src/mlib/str.h
@@ -975,6 +975,54 @@ mlib_strlen (const char *s)
return r;
}
+/**
+ * @brief Copy characters into the destination, guaranteed null-terminated and
+ * bounds checked.
+ *
+ * @param dst Pointer to the beginning of the destination array.
+ * @param dst_bufsize The size of the destination array, in characters. MUST be
+ * greater than zero.
+ * @param src Pointer to the beginning of a null-terminated character array.
+ * @param src_bufsize The size of the array pointed-to by `src`.
+ * @return size_t The number `R` of characters written (NOT including the null
+ * terminator). R is guaranteed to be less than dst_bufsize, and
+ * less-than-or-equal-to src_bufsize.
+ *
+ * @note Characters beyond (dst + R) are unmodified. dst[R] is guaranteed to
+ * be a null terminator.
+ */
+static mlib_constexpr_fn size_t
+mlib_strnmcopy (char *dst,
+ size_t dst_bufsize,
+ const char *src,
+ size_t src_bufsize)
+{
+ // No empty destination, since we *must* write a null terminator:
+ assert (dst_bufsize > 0);
+ // The maximum number of characters in the dest is one less than the buffer
+ // size, since we need room for the null terminator:
+ const size_t dstlen = dst_bufsize - 1u;
+ // The actual maximum number of characters we can copy is the less of the
+ // source length and the dest length:
+ const size_t minlen = dstlen < src_bufsize ? dstlen : src_bufsize;
+ // Track what we copy:
+ size_t ncopied = 0;
+ while (ncopied != minlen // Stop if we hit our character limit
+ && *src != 0 // Or if we hit the null terminator in the source
+ ) {
+ // Copy:
+ *dst = *src;
+ // Advance:
+ ++dst;
+ ++src;
+ ++ncopied;
+ }
+ // "dst" now points past the final character we copied (if any), and is still
+ // in-bounds. This will be the null terminator.
+ *dst = 0;
+ return ncopied;
+}
+
MLIB_C_LINKAGE_END
#endif // MONGOCRYPT_STR_PRIVATE_H
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt-buffer-private.h b/src/third_party/libmongocrypt/dist/src/mongocrypt-buffer-private.h
index fa25876d71d..2d77fb9125a 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt-buffer-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt-buffer-private.h
@@ -22,6 +22,7 @@
#include "mongocrypt-compat.h"
#define UUID_LEN 16
+#define PRF_LEN 32
struct _mongocrypt_binary_t;
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt-ctx-encrypt.c b/src/third_party/libmongocrypt/dist/src/mongocrypt-ctx-encrypt.c
index 8c77cd75176..63612d43bd5 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt-ctx-encrypt.c
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt-ctx-encrypt.c
@@ -1075,15 +1075,25 @@ _try_run_csfle_marking (mongocrypt_ctx_t *ctx)
mongocrypt_binary_t *marked =
mongocrypt_binary_new_from_data (marked_bson, marked_bson_len);
if (!_mongo_feed_markings (ctx, marked)) {
- _mongocrypt_ctx_fail_w_msg (
- ctx, "Consuming the generated csfle markings failed");
+ // Wrap error with additional information.
+ _mongocrypt_set_error (
+ ctx->status,
+ MONGOCRYPT_STATUS_ERROR_CLIENT,
+ MONGOCRYPT_GENERIC_ERROR_CODE,
+ "Consuming the generated csfle markings failed: %s",
+ mongocrypt_status_message (ctx->status, NULL /* len */));
goto fail_feed_markings;
}
okay = _mongo_done_markings (ctx);
if (!okay) {
- _mongocrypt_ctx_fail_w_msg (
- ctx, "Finalizing the generated csfle markings failed");
+ // Wrap error with additional information.
+ _mongocrypt_set_error (
+ ctx->status,
+ MONGOCRYPT_STATUS_ERROR_CLIENT,
+ MONGOCRYPT_GENERIC_ERROR_CODE,
+ "Finalizing the generated csfle markings failed: %s",
+ mongocrypt_status_message (ctx->status, NULL /* len */));
}
fail_feed_markings:
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt-key-broker.c b/src/third_party/libmongocrypt/dist/src/mongocrypt-key-broker.c
index 83433aeb5b9..fbb6b20ac0e 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt-key-broker.c
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt-key-broker.c
@@ -151,7 +151,7 @@ _key_broker_fail_w_msg (_mongocrypt_key_broker_t *kb, const char *msg)
kb->state = KB_ERROR;
status = kb->status;
- CLIENT_ERR (msg);
+ CLIENT_ERR ("%s", msg);
return false;
}
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt-marking.c b/src/third_party/libmongocrypt/dist/src/mongocrypt-marking.c
index 3062d046d9c..a01c97414ab 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt-marking.c
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt-marking.c
@@ -701,6 +701,22 @@ get_edges (mc_FLE2RangeInsertSpec_t *insertSpec,
return mc_getEdgesDouble (args, status);
}
+ else if (value_type == BSON_TYPE_DECIMAL128) {
+ const mc_dec128 value = mc_dec128_from_bson_iter (&insertSpec->v);
+ mc_getEdgesDecimal128_args_t args = {
+ .value = value,
+ .sparsity = sparsity,
+ };
+ if (insertSpec->precision.set) {
+ const mc_dec128 min = mc_dec128_from_bson_iter (&insertSpec->min);
+ const mc_dec128 max = mc_dec128_from_bson_iter (&insertSpec->max);
+ args.min = OPT_MC_DEC128 (min);
+ args.max = OPT_MC_DEC128 (max);
+ args.precision = insertSpec->precision;
+ }
+ return mc_getEdgesDecimal128 (args, status);
+ }
+
CLIENT_ERR ("unsupported BSON type: %s for range",
mc_bson_type_to_string (value_type));
@@ -1160,10 +1176,30 @@ mc_get_mincover_from_FLE2RangeFindSpec (mc_FLE2RangeFindSpec_t *findSpec,
}
return mc_getMincoverDouble (args, status);
}
- case BSON_TYPE_DECIMAL128:
- CLIENT_ERR ("FLE2 find not yet implemented for type: %s",
- mc_bson_type_to_string (bsonType));
- return NULL;
+ case BSON_TYPE_DECIMAL128: {
+ BSON_ASSERT (bson_iter_type (&lowerBound) == BSON_TYPE_DECIMAL128);
+ BSON_ASSERT (bson_iter_type (&upperBound) == BSON_TYPE_DECIMAL128);
+ BSON_ASSERT (bson_iter_type (&findSpec->edgesInfo.value.indexMin) ==
+ BSON_TYPE_DECIMAL128);
+ BSON_ASSERT (bson_iter_type (&findSpec->edgesInfo.value.indexMax) ==
+ BSON_TYPE_DECIMAL128);
+
+ mc_getMincoverDecimal128_args_t args = {
+ .lowerBound = mc_dec128_from_bson_iter (&lowerBound),
+ .includeLowerBound = includeLowerBound,
+ .upperBound = mc_dec128_from_bson_iter (&upperBound),
+ .includeUpperBound = includeUpperBound,
+ .sparsity = sparsity,
+ };
+ if (findSpec->edgesInfo.value.precision.set) {
+ args.min = OPT_MC_DEC128 (
+ mc_dec128_from_bson_iter (&findSpec->edgesInfo.value.indexMin));
+ args.max = OPT_MC_DEC128 (
+ mc_dec128_from_bson_iter (&findSpec->edgesInfo.value.indexMax));
+ args.precision = findSpec->edgesInfo.value.precision;
+ }
+ return mc_getMincoverDecimal128 (args, status);
+ }
case BSON_TYPE_EOD:
case BSON_TYPE_UTF8:
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt-private.h b/src/third_party/libmongocrypt/dist/src/mongocrypt-private.h
index 2e8a24320b9..458f7676279 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt-private.h
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt-private.h
@@ -33,6 +33,8 @@
#include "mongo_crypt-v1.h"
+#include <mlib/macros.h>
+
#define MONGOCRYPT_GENERIC_ERROR_CODE 1
@@ -64,7 +66,16 @@ tmp_json (const bson_t *bson);
const char *
tmp_buf (const _mongocrypt_buffer_t *buf);
-
+// _mongocrypt_set_error sets an error status.
+// `status->message` is set after evaluating `format` and variadic args.
+// It is safe to uses a `status->message` as an argument to wrap an error. For example:
+// _mongocrypt_set_error (
+// status,
+// MONGOCRYPT_STATUS_ERROR_CLIENT,
+// MONGOCRYPT_GENERIC_ERROR_CODE,
+// "Error occurred. Original error: %s",
+// mongocrypt_status_message (status, NULL /* len */));
+MLIB_ANNOTATE_PRINTF (4, 5)
void
_mongocrypt_set_error (mongocrypt_status_t *status,
mongocrypt_status_type_t type,
diff --git a/src/third_party/libmongocrypt/dist/src/mongocrypt.c b/src/third_party/libmongocrypt/dist/src/mongocrypt.c
index 5e2dbaad278..5b4f7888803 100644
--- a/src/third_party/libmongocrypt/dist/src/mongocrypt.c
+++ b/src/third_party/libmongocrypt/dist/src/mongocrypt.c
@@ -310,7 +310,7 @@ mongocrypt_setopt_schema_map (mongocrypt_t *crypt,
}
if (!bson_validate_with_error (&tmp, BSON_VALIDATE_NONE, &bson_err)) {
- CLIENT_ERR (bson_err.message);
+ CLIENT_ERR ("%s", bson_err.message);
return false;
}
@@ -353,7 +353,7 @@ mongocrypt_setopt_encrypted_field_config_map (mongocrypt_t *crypt,
}
if (!bson_validate_with_error (&as_bson, BSON_VALIDATE_NONE, &bson_err)) {
- CLIENT_ERR (bson_err.message);
+ CLIENT_ERR ("%s", bson_err.message);
return false;
}
diff --git a/src/third_party/libmongocrypt/import.sh b/src/third_party/libmongocrypt/import.sh
index a96884fe6f7..df923ef0203 100755
--- a/src/third_party/libmongocrypt/import.sh
+++ b/src/third_party/libmongocrypt/import.sh
@@ -18,7 +18,7 @@ if grep -q Microsoft /proc/version; then
fi
NAME=libmongocrypt
-REVISION=2c564d555b168e9bdb60ade186b6f3aa759e010b
+REVISION=d01892a44db2504253274fc51c1c51c76f467881
if grep -q Microsoft /proc/version; then
SRC_ROOT=$(wslpath -u $(powershell.exe -Command "Get-ChildItem Env:TEMP | Get-Content | Write-Host"))