Repository: randombit/botan
Pull request #3993 (2024-04-09 14:18:28)

[std::span] some pubkey things
That's just some helper stuff for #3985.


Patch:
diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp
index 6fa42fd6f..2761b0dd0 100644
--- a/src/cli/utils.cpp
+++ b/src/cli/utils.cpp
@@ -66,19 +66,12 @@ class Print_Help final : public Command {
          oss << "Available commands:\n\n";
 
          for(const auto& commands : grouped_commands) {
-            const std::string group = commands.first;
-            if(group.empty()) {
-               // ???
+            std::string desc = commands.first;
+            if(desc.empty()) {
                continue;
             }
 
-            auto descr = groups_description.find(group);
-            if(descr != groups_description.end()) {
-               oss << descr->second;
-            } else {
-               oss << group;
-            }
-            oss << ":\n";
+            oss << Botan::search_map(groups_description, desc, desc) << ":\n";
             for(const auto& cmd : commands.second) {
                oss << "   " << std::setw(16) << std::left << cmd->cmd_name() << "   " << cmd->description() << "\n";
             }
diff --git a/src/lib/math/mp/mp_asmi.h b/src/lib/math/mp/mp_asmi.h
index 050ea8085..588a20dfd 100644
--- a/src/lib/math/mp/mp_asmi.h
+++ b/src/lib/math/mp/mp_asmi.h
@@ -17,8 +17,14 @@
 
 namespace Botan {
 
-#if defined(BOTAN_USE_GCC_INLINE_ASM) && defined(BOTAN_TARGET_ARCH_IS_X86_64)
-   #define BOTAN_MP_USE_X86_64_ASM
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+   #if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
+      #define BOTAN_MP_USE_X86_32_ASM
+   #endif
+
+   #if defined(BOTAN_TARGET_ARCH_IS_X86_64)
+      #define BOTAN_MP_USE_X86_64_ASM
+   #endif
 #endif
 
 /*
@@ -62,6 +68,21 @@ struct WordInfo<uint64_t> {
 */
 template <WordType W>
 inline constexpr auto word_madd2(W a, W b, W* c) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         mull %[b]
+         addl %[c],%[a]
+         adcl $0,%[carry]
+         )"
+          : [a] "=a"(a), [b] "=rm"(b), [carry] "=&d"(*c)
+          : "0"(a), "1"(b), [c] "g"(*c)
+          : "cc");
+
+      return a;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -88,6 +109,25 @@ inline constexpr auto word_madd2(W a, W b, W* c) -> W {
 */
 template <WordType W>
 inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         mull %[b]
+
+         addl %[c],%[a]
+         adcl $0,%[carry]
+
+         addl %[d],%[a]
+         adcl $0,%[carry]
+         )"
+          : [a] "=a"(a), [b] "=rm"(b), [carry] "=&d"(*d)
+          : "0"(a), "1"(b), [c] "g"(c), [d] "g"(*d)
+          : "cc");
+
+      return a;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -113,19 +153,42 @@ inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
    return static_cast<W>(s);
 }
 
-#if defined(BOTAN_MP_USE_X86_64_ASM)
+#if defined(BOTAN_MP_USE_X86_32_ASM)
 
-   #define ASM(x) x "\n\t"
+   #define ADDSUB2_OP(OPERATION, INDEX)        \
+      ASM("movl 4*" #INDEX "(%[y]), %[carry]") \
+      ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])")
 
-   #define DO_8_TIMES(MACRO, ARG) \
-      MACRO(ARG, 0)               \
-      MACRO(ARG, 1)               \
-      MACRO(ARG, 2)               \
-      MACRO(ARG, 3)               \
-      MACRO(ARG, 4)               \
-      MACRO(ARG, 5)               \
-      MACRO(ARG, 6)               \
-      MACRO(ARG, 7)
+   #define ADDSUB3_OP(OPERATION, INDEX)              \
+      ASM("movl 4*" #INDEX "(%[x]), %[carry]")       \
+      ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \
+      ASM("movl %[carry], 4*" #INDEX "(%[z])")
+
+   #define LINMUL_OP(WRITE_TO, INDEX)      \
+      ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+      ASM("mull %[y]")                     \
+      ASM("addl %[carry],%%eax")           \
+      ASM("adcl $0,%%edx")                 \
+      ASM("movl %%edx,%[carry]")           \
+      ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])")
+
+   #define MULADD_OP(IGNORED, INDEX)       \
+      ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+      ASM("mull %[y]")                     \
+      ASM("addl %[carry],%%eax")           \
+      ASM("adcl $0,%%edx")                 \
+      ASM("addl 4*" #INDEX "(%[z]),%%eax") \
+      ASM("adcl $0,%%edx")                 \
+      ASM("movl %%edx,%[carry]")           \
+      ASM("movl %%eax, 4*" #INDEX " (%[z])")
+
+   #define ADD_OR_SUBTRACT(CORE_CODE) \
+      ASM("rorl %[carry]")            \
+      CORE_CODE                       \
+      ASM("sbbl %[carry],%[carry]")   \
+      ASM("negl %[carry]")
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
 
    #define ADDSUB2_OP(OPERATION, INDEX)        \
       ASM("movq 8*" #INDEX "(%[y]), %[carry]") \
@@ -162,11 +225,37 @@ inline constexpr auto word_madd3(W a, W b, W c, W* d) -> W {
 
 #endif
 
+#if defined(ADD_OR_SUBTRACT)
+
+   #define ASM(x) x "\n\t"
+
+   #define DO_8_TIMES(MACRO, ARG) \
+      MACRO(ARG, 0)               \
+      MACRO(ARG, 1)               \
+      MACRO(ARG, 2)               \
+      MACRO(ARG, 3)               \
+      MACRO(ARG, 4)               \
+      MACRO(ARG, 5)               \
+      MACRO(ARG, 6)               \
+      MACRO(ARG, 7)
+
+#endif
+
 /*
 * Word Addition
 */
 template <WordType W>
 inline constexpr auto word_add(W x, W y, W* carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]"))
+          : [x] "=r"(x), [carry] "=r"(*carry)
+          : "0"(x), [y] "rm"(y), "1"(*carry)
+          : "cc");
+      return x;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]"))
@@ -189,6 +278,16 @@ inline constexpr auto word_add(W x, W y, W* carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq"))
@@ -215,6 +314,16 @@ inline constexpr auto word8_add2(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), [z] "r"(z), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq"))
@@ -241,6 +350,16 @@ inline constexpr auto word8_add3(W z[8], const W x[8], const W y[8], W carry) ->
 */
 template <WordType W>
 inline constexpr auto word_sub(W x, W y, W* carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]"))
+          : [x] "=r"(x), [carry] "=r"(*carry)
+          : "0"(x), [y] "rm"(y), "1"(*carry)
+          : "cc");
+      return x;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]"))
@@ -263,6 +382,16 @@ inline constexpr auto word_sub(W x, W y, W* carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq"))
@@ -289,6 +418,16 @@ inline constexpr auto word8_sub2(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub2_rev(W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(y), [y] "r"(x), [z] "r"(x), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
@@ -315,6 +454,16 @@ inline constexpr auto word8_sub2_rev(W x[8], const W y[8], W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "r"(y), [z] "r"(z), "0"(carry)
+          : "cc", "memory");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
@@ -341,6 +490,16 @@ inline constexpr auto word8_sub3(W z[8], const W x[8], const W y[8], W carry) ->
 */
 template <WordType W>
 inline constexpr auto word8_linmul2(W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(LINMUL_OP, "x")
+          : [carry] "=r"(carry)
+          : [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(LINMUL_OP, "x")
@@ -367,6 +526,16 @@ inline constexpr auto word8_linmul2(W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(LINMUL_OP, "z")
+          : [carry] "=r"(carry)
+          : [z] "r"(z), [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(LINMUL_OP, "z")
@@ -393,6 +562,16 @@ inline constexpr auto word8_linmul3(W z[8], const W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr auto word8_madd3(W z[8], const W x[8], W y, W carry) -> W {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(DO_8_TIMES(MULADD_OP, "")
+          : [carry] "=r"(carry)
+          : [z] "r"(z), [x] "r"(x), [y] "rm"(y), "0"(carry)
+          : "cc", "%eax", "%edx");
+      return carry;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(DO_8_TIMES(MULADD_OP, "")
@@ -420,6 +599,24 @@ inline constexpr auto word8_madd3(W z[8], const W x[8], W y, W carry) -> W {
 */
 template <WordType W>
 inline constexpr void word3_muladd(W* w2, W* w1, W* w0, W x, W y) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      W z0 = 0, z1 = 0;
+
+      asm("mull %[y]" : "=a"(z0), "=d"(z1) : "a"(x), [y] "rm"(y) : "cc");
+
+      asm(R"(
+          addl %[z0],%[w0]
+          adcl %[z1],%[w1]
+          adcl $0,%[w2]
+          )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [z0] "r"(z0), [z1] "r"(z1), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       W z0 = 0, z1 = 0;
@@ -450,6 +647,20 @@ inline constexpr void word3_muladd(W* w2, W* w1, W* w0, W x, W y) {
 */
 template <WordType W>
 inline constexpr void word3_add(W* w2, W* w1, W* w0, W x) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      asm(R"(
+         addl %[x],%[w0]
+         adcl $0,%[w1]
+         adcl $0,%[w2]
+         )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [x] "r"(x), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       asm(R"(
@@ -477,6 +688,28 @@ inline constexpr void word3_add(W* w2, W* w1, W* w0, W x) {
 */
 template <WordType W>
 inline constexpr void word3_muladd_2(W* w2, W* w1, W* w0, W x, W y) {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+   if(std::same_as<W, uint32_t> && !std::is_constant_evaluated()) {
+      W z0 = 0, z1 = 0;
+
+      asm("mull %[y]" : "=a"(z0), "=d"(z1) : "a"(x), [y] "rm"(y) : "cc");
+
+      asm(R"(
+         addl %[z0],%[w0]
+         adcl %[z1],%[w1]
+         adcl $0,%[w2]
+
+         addl %[z0],%[w0]
+         adcl %[z1],%[w1]
+         adcl $0,%[w2]
+         )"
+          : [w0] "=r"(*w0), [w1] "=r"(*w1), [w2] "=r"(*w2)
+          : [z0] "r"(z0), [z1] "r"(z1), "0"(*w0), "1"(*w1), "2"(*w2)
+          : "cc");
+      return;
+   }
+#endif
+
 #if defined(BOTAN_MP_USE_X86_64_ASM)
    if(std::same_as<W, uint64_t> && !std::is_constant_evaluated()) {
       W z0 = 0, z1 = 0;
diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h
index 2fac3218a..6dc809cf0 100644
--- a/src/lib/math/mp/mp_core.h
+++ b/src/lib/math/mp/mp_core.h
@@ -137,7 +137,10 @@ inline constexpr void bigint_cnd_add_or_sub(CT::Mask<W> mask, W x[], const W y[]
    for(size_t i = 0; i != blocks; i += 8) {
       carry = word8_add3(t0, x + i, y + i, carry);
       borrow = word8_sub3(t1, x + i, y + i, borrow);
-      mask.select_n(x + i, t0, t1, 8);
+
+      for(size_t j = 0; j != 8; ++j) {
+         x[i + j] = mask.select(t0[j], t1[j]);
+      }
    }
 
    for(size_t i = blocks; i != size; ++i) {
@@ -170,7 +173,10 @@ inline constexpr auto bigint_cnd_addsub(CT::Mask<W> mask, W x[], const W y[], co
    for(size_t i = 0; i != blocks; i += 8) {
       carry = word8_add3(t0, x + i, y + i, carry);
       borrow = word8_sub3(t1, x + i, z + i, borrow);
-      mask.select_n(x + i, t0, t1, 8);
+
+      for(size_t j = 0; j != 8; ++j) {
+         x[i + j] = mask.select(t0[j], t1[j]);
+      }
    }
 
    for(size_t i = blocks; i != size; ++i) {
diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp
index 715dda180..dd70c3561 100644
--- a/src/lib/pubkey/curve25519/curve25519.cpp
+++ b/src/lib/pubkey/curve25519/curve25519.cpp
@@ -24,7 +24,7 @@ namespace {
 
 void size_check(size_t size, const char* thing) {
    if(size != 32) {
-      throw Decoding_Error(fmt("Invalid size {} for Curve2551 {}", size, thing));
+      throw Decoding_Error(fmt("Invalid size {} for Curve25519 {}", size, thing));
    }
 }
 
@@ -44,8 +44,11 @@ bool Curve25519_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*stro
    return true;  // no tests possible?
 }
 
-Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
-   m_public.assign(key_bits.begin(), key_bits.end());
+Curve25519_PublicKey::Curve25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) :
+      Curve25519_PublicKey(key_bits) {}
+
+Curve25519_PublicKey::Curve25519_PublicKey(std::span<const uint8_t> pub) {
+   m_public.assign(pub.begin(), pub.end());
 
    size_check(m_public.size(), "public key");
 }
diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h
index 422479657..d992e5c3a 100644
--- a/src/lib/pubkey/curve25519/curve25519.h
+++ b/src/lib/pubkey/curve25519/curve25519.h
@@ -43,13 +43,7 @@ class BOTAN_PUBLIC_API(2, 0) Curve25519_PublicKey : public virtual Public_Key {
       * Create a Curve25519 Public Key.
       * @param pub 32-byte raw public key
       */
-      explicit Curve25519_PublicKey(const std::vector<uint8_t>& pub) : m_public(pub) {}
-
-      /**
-      * Create a Curve25519 Public Key.
-      * @param pub 32-byte raw public key
-      */
-      explicit Curve25519_PublicKey(const secure_vector<uint8_t>& pub) : m_public(pub.begin(), pub.end()) {}
+      explicit Curve25519_PublicKey(std::span<const uint8_t> pub);
 
    protected:
       Curve25519_PublicKey() = default;
diff --git a/src/lib/pubkey/ec_group/ec_point.h b/src/lib/pubkey/ec_group/ec_point.h
index ad473b18a..5bd2926df 100644
--- a/src/lib/pubkey/ec_group/ec_point.h
+++ b/src/lib/pubkey/ec_group/ec_point.h
@@ -392,8 +392,7 @@ EC_Point BOTAN_PUBLIC_API(2, 0) OS2ECP(const uint8_t data[], size_t data_len, co
 std::pair<BigInt, BigInt> BOTAN_UNSTABLE_API
 OS2ECP(const uint8_t data[], size_t data_len, const BigInt& curve_p, const BigInt& curve_a, const BigInt& curve_b);
 
-template <typename Alloc>
-EC_Point OS2ECP(const std::vector<uint8_t, Alloc>& data, const CurveGFp& curve) {
+inline EC_Point OS2ECP(std::span<const uint8_t> data, const CurveGFp& curve) {
    return OS2ECP(data.data(), data.size(), curve);
 }
 
diff --git a/src/lib/pubkey/ed25519/ed25519.h b/src/lib/pubkey/ed25519/ed25519.h
index d136c035a..9e8929034 100644
--- a/src/lib/pubkey/ed25519/ed25519.h
+++ b/src/lib/pubkey/ed25519/ed25519.h
@@ -42,8 +42,7 @@ class BOTAN_PUBLIC_API(2, 2) Ed25519_PublicKey : public virtual Public_Key {
       */
       Ed25519_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits);
 
-      template <typename Alloc>
-      Ed25519_PublicKey(const std::vector<uint8_t, Alloc>& pub) : Ed25519_PublicKey(pub.data(), pub.size()) {}
+      Ed25519_PublicKey(std::span<const uint8_t> pub) : Ed25519_PublicKey(pub.data(), pub.size()) {}
 
       Ed25519_PublicKey(const uint8_t pub_key[], size_t len);
 
diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp
index c88c3894f..4c2dd35bd 100644
--- a/src/lib/utils/http_util/http_util.cpp
+++ b/src/lib/utils/http_util/http_util.cpp
@@ -214,9 +214,9 @@ Response http_sync(const http_exch_fn& http_transact,
       resp_body.insert(resp_body.end(), buf.data(), &buf[got]);
    }
 
-   auto cl_hdr = headers.find("Content-Length");
-   if(cl_hdr != headers.end()) {
-      const std::string header_size = cl_hdr->second;
+   const std::string header_size = search_map(headers, std::string("Content-Length"));
+
+   if(!header_size.empty()) {
       if(resp_body.size() != to_u32bit(header_size)) {
          throw HTTP_Error(fmt("Content-Length disagreement, header says {} got {}", header_size, resp_body.size()));
       }
diff --git a/src/lib/utils/stl_util.h b/src/lib/utils/stl_util.h
index 2629350f2..26f624370 100644
--- a/src/lib/utils/stl_util.h
+++ b/src/lib/utils/stl_util.h
@@ -11,7 +11,9 @@
 
 #include <algorithm>
 #include <functional>
+#include <map>
 #include <optional>
+#include <set>
 #include <span>
 #include <string>
 #include <tuple>
@@ -52,6 +54,63 @@ RetT reduce(const std::vector<KeyT>& keys, RetT acc, ReducerT reducer)
    return acc;
 }
 
+/**
+* Return the keys of a map as a std::set
+*/
+template <typename K, typename V>
+std::set<K> map_keys_as_set(const std::map<K, V>& kv) {
+   std::set<K> s;
+   for(auto&& i : kv) {
+      s.insert(i.first);
+   }
+   return s;
+}
+
+/**
+* Return the keys of a multimap as a std::set
+*/
+template <typename K, typename V>
+std::set<K> map_keys_as_set(const std::multimap<K, V>& kv) {
+   std::set<K> s;
+   for(auto&& i : kv) {
+      s.insert(i.first);
+   }
+   return s;
+}
+
+/*
+* Searching through a std::map
+* @param mapping the map to search
+* @param key is what to look for
+* @param null_result is the value to return if key is not in mapping
+* @return mapping[key] or null_result
+*/
+template <typename K, typename V>
+inline V search_map(const std::map<K, V>& mapping, const K& key, const V& null_result = V()) {
+   auto i = mapping.find(key);
+   if(i == mapping.end()) {
+      return null_result;
+   }
+   return i->second;
+}
+
+template <typename K, typename V, typename R>
+inline R search_map(const std::map<K, V>& mapping, const K& key, const R& null_result, const R& found_result) {
+   auto i = mapping.find(key);
+   if(i == mapping.end()) {
+      return null_result;
+   }
+   return found_result;
+}
+
+/*
+* Insert a key/value pair into a multimap
+*/
+template <typename K, typename V>
+void multimap_insert(std::multimap<K, V>& multimap, const K& key, const V& value) {
+   multimap.insert(std::make_pair(key, value));
+}
+
 /**
 * Existence check for values
 */
diff --git a/src/lib/x509/asn1_alt_name.cpp b/src/lib/x509/asn1_alt_name.cpp
index 8fff9145c..08bace9e3 100644
--- a/src/lib/x509/asn1_alt_name.cpp
+++ b/src/lib/x509/asn1_alt_name.cpp
@@ -56,7 +56,7 @@ void AlternativeName::add_othername(const OID& oid, std::string_view value, ASN1
    if(value.empty()) {
       return;
    }
-   m_othernames.emplace(oid, ASN1_String{value, type});
+   multimap_insert(m_othernames, oid, ASN1_String(value, type));
 }
 
 /*
@@ -70,7 +70,7 @@ std::multimap<std::string, std::string> AlternativeName::contents() const {
    }
 
    for(const auto& othername : m_othernames) {
-      names.emplace(othername.first.to_formatted_string(), othername.second.value());
+      multimap_insert(names, othername.first.to_formatted_string(), othername.second.value());
    }
 
    return names;
diff --git a/src/lib/x509/x509_dn.cpp b/src/lib/x509/x509_dn.cpp
index 1f7a9e21c..bf2a53578 100644
--- a/src/lib/x509/x509_dn.cpp
+++ b/src/lib/x509/x509_dn.cpp
@@ -113,7 +113,7 @@ std::multimap<OID, std::string> X509_DN::get_attributes() const {
    std::multimap<OID, std::string> retval;
 
    for(auto& i : m_rdn) {
-      retval.emplace(i.first, i.second.value());
+      multimap_insert(retval, i.first, i.second.value());
    }
    return retval;
 }
@@ -125,7 +125,7 @@ std::multimap<std::string, std::string> X509_DN::contents() const {
    std::multimap<std::string, std::string> retval;
 
    for(auto& i : m_rdn) {
-      retval.emplace(i.first.to_formatted_string(), i.second.value());
+      multimap_insert(retval, i.first.to_formatted_string(), i.second.value());
    }
    return retval;
 }


Test patch:
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index 683fb2c23..c6ce80b78 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -519,21 +519,9 @@ class Test_Registry {
          return nullptr;
       }
 
-      std::set<std::string> registered_tests() const {
-         std::set<std::string> s;
-         for(auto&& i : m_tests) {
-            s.insert(i.first);
-         }
-         return s;
-      }
+      std::set<std::string> registered_tests() const { return Botan::map_keys_as_set(m_tests); }
 
-      std::set<std::string> registered_test_categories() const {
-         std::set<std::string> s;
-         for(auto&& i : m_categories) {
-            s.insert(i.first);
-         }
-         return s;
-      }
+      std::set<std::string> registered_test_categories() const { return Botan::map_keys_as_set(m_categories); }
 
       std::vector<std::string> filter_registered_tests(const std::vector<std::string>& requested,
                                                        const std::set<std::string>& to_be_skipped) {