Repository: randombit/botan
Pull request #2409 (2020-09-29 15:31:11)

If a DL_Group or EC_Group comes from a trusted source skip verification
(Unless "strong" is enabled which performs the full checks as usual)


Patch:
diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp
index 09ad76d95..6e662eb0a 100644
--- a/src/cli/speed.cpp
+++ b/src/cli/speed.cpp
@@ -1672,9 +1672,9 @@ class Speed final : public Command
 
             if(dec_timer->under(msec))
                {
-               auto dec_pt = dec_timer->run([&]() { return dec.decrypt(ciphertext); });
+               const auto dec_pt = dec_timer->run([&]() { return dec.decrypt(ciphertext); });
 
-               if(dec_pt != plaintext) // sanity check
+               if(!(dec_pt == plaintext)) // sanity check
                   {
                   error_output() << "Bad roundtrip in PK encrypt/decrypt bench\n";
                   }
diff --git a/src/lib/math/numbertheory/numthry.cpp b/src/lib/math/numbertheory/numthry.cpp
index 4c2e61533..06d837801 100644
--- a/src/lib/math/numbertheory/numthry.cpp
+++ b/src/lib/math/numbertheory/numthry.cpp
@@ -236,7 +236,10 @@ bool is_prime(const BigInt& n,
       if(is_miller_rabin_probable_prime(n, mod_n, rng, t) == false)
          return false;
 
-      return is_lucas_probable_prime(n, mod_n);
+      if(is_random)
+         return true;
+      else
+         return is_lucas_probable_prime(n, mod_n);
       }
    else
       {
diff --git a/src/lib/pubkey/dl_group/dl_group.cpp b/src/lib/pubkey/dl_group/dl_group.cpp
index 804859044..b6b5d5f44 100644
--- a/src/lib/pubkey/dl_group/dl_group.cpp
+++ b/src/lib/pubkey/dl_group/dl_group.cpp
@@ -20,7 +20,7 @@ namespace Botan {
 class DL_Group_Data final
    {
    public:
-      DL_Group_Data(const BigInt& p, const BigInt& q, const BigInt& g) :
+      DL_Group_Data(const BigInt& p, const BigInt& q, const BigInt& g, DL_Group_Source source) :
          m_p(p), m_q(q), m_g(g),
          m_mod_p(p),
          m_mod_q(q),
@@ -29,7 +29,8 @@ class DL_Group_Data final
          m_p_bits(p.bits()),
          m_q_bits(q.bits()),
          m_estimated_strength(dl_work_factor(m_p_bits)),
-         m_exponent_bits(dl_exponent_size(m_p_bits))
+         m_exponent_bits(dl_exponent_size(m_p_bits)),
+         m_source(source)
          {
          }
 
@@ -86,6 +87,8 @@ class DL_Group_Data final
             throw Invalid_State("DL_Group::" + function + " q is not set for this group");
          }
 
+      DL_Group_Source source() const { return m_source; }
+
    private:
       BigInt m_p;
       BigInt m_q;
@@ -98,10 +101,13 @@ class DL_Group_Data final
       size_t m_q_bits;
       size_t m_estimated_strength;
       size_t m_exponent_bits;
+      DL_Group_Source m_source;
    };
 
 //static
-std::shared_ptr<DL_Group_Data> DL_Group::BER_decode_DL_group(const uint8_t data[], size_t data_len, DL_Group::Format format)
+std::shared_ptr<DL_Group_Data> DL_Group::BER_decode_DL_group(const uint8_t data[], size_t data_len,
+                                                             DL_Group::Format format,
+                                                             DL_Group_Source source)
    {
    BigInt p, q, g;
 
@@ -132,7 +138,7 @@ std::shared_ptr<DL_Group_Data> DL_Group::BER_decode_DL_group(const uint8_t data[
    else
       throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
 
-   return std::make_shared<DL_Group_Data>(p, q, g);
+   return std::make_shared<DL_Group_Data>(p, q, g, source);
    }
 
 //static
@@ -145,7 +151,7 @@ DL_Group::load_DL_group_info(const char* p_str,
    const BigInt q(q_str);
    const BigInt g(g_str);
 
-   return std::make_shared<DL_Group_Data>(p, q, g);
+   return std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::Builtin);
    }
 
 //static
@@ -157,7 +163,7 @@ DL_Group::load_DL_group_info(const char* p_str,
    const BigInt q = (p - 1) / 2;
    const BigInt g(g_str);
 
-   return std::make_shared<DL_Group_Data>(p, q, g);
+   return std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::Builtin);
    }
 
 namespace {
@@ -192,7 +198,7 @@ DL_Group::DL_Group(const std::string& str)
          const std::vector<uint8_t> ber = unlock(PEM_Code::decode(str, label));
          Format format = pem_label_to_dl_format(label);
 
-         m_data = BER_decode_DL_group(ber.data(), ber.size(), format);
+         m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource);
          }
       catch(...) {}
       }
@@ -259,7 +265,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
             }
          }
 
-      m_data = std::make_shared<DL_Group_Data>(p, q, g);
+      m_data = std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::RandomlyGenerated);
       }
    else if(type == Prime_Subgroup)
       {
@@ -277,7 +283,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
          }
 
       const BigInt g = make_dsa_generator(p, q);
-      m_data = std::make_shared<DL_Group_Data>(p, q, g);
+      m_data = std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::RandomlyGenerated);
       }
    else if(type == DSA_Kosherizer)
       {
@@ -287,7 +293,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
       BigInt p, q;
       generate_dsa_primes(rng, p, q, pbits, qbits);
       const BigInt g = make_dsa_generator(p, q);
-      m_data = std::make_shared<DL_Group_Data>(p, q, g);
+      m_data = std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::RandomlyGenerated);
       }
    else
       {
@@ -309,7 +315,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
 
    BigInt g = make_dsa_generator(p, q);
 
-   m_data = std::make_shared<DL_Group_Data>(p, q, g);
+   m_data = std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::RandomlyGenerated);
    }
 
 /*
@@ -317,7 +323,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
 */
 DL_Group::DL_Group(const BigInt& p, const BigInt& g)
    {
-   m_data = std::make_shared<DL_Group_Data>(p, 0, g);
+   m_data = std::make_shared<DL_Group_Data>(p, 0, g, DL_Group_Source::ExternalSource);
    }
 
 /*
@@ -325,7 +331,7 @@ DL_Group::DL_Group(const BigInt& p, const BigInt& g)
 */
 DL_Group::DL_Group(const BigInt& p, const BigInt& q, const BigInt& g)
    {
-   m_data = std::make_shared<DL_Group_Data>(p, q, g);
+   m_data = std::make_shared<DL_Group_Data>(p, q, g, DL_Group_Source::ExternalSource);
    }
 
 const DL_Group_Data& DL_Group::data() const
@@ -372,6 +378,11 @@ bool DL_Group::verify_element_pair(const BigInt& y, const BigInt& x) const
 bool DL_Group::verify_group(RandomNumberGenerator& rng,
                             bool strong) const
    {
+   const bool from_builtin = (source() == DL_Group_Source::Builtin);
+
+   if(!strong && from_builtin)
+      return true;
+
    const BigInt& p = get_p();
    const BigInt& q = get_q();
    const BigInt& g = get_g();
@@ -379,7 +390,8 @@ bool DL_Group::verify_group(RandomNumberGenerator& rng,
    if(g < 2 || p < 3 || q < 0)
       return false;
 
-   const size_t prob = (strong) ? 128 : 10;
+   const size_t test_prob = 128;
+   const bool is_randomly_generated = (source() != DL_Group_Source::ExternalSource);
 
    if(q != 0)
       {
@@ -391,16 +403,17 @@ bool DL_Group::verify_group(RandomNumberGenerator& rng,
          {
          return false;
          }
-      if(!is_prime(q, rng, prob))
+      if(!is_prime(q, rng, test_prob, is_randomly_generated))
          {
          return false;
          }
       }
 
-   if(!is_prime(p, rng, prob))
+   if(!is_prime(p, rng, test_prob, is_randomly_generated))
       {
       return false;
       }
+
    return true;
    }
 
@@ -527,6 +540,11 @@ BigInt DL_Group::power_g_p(const BigInt& x, size_t max_x_bits) const
    return data().power_g_p(x, max_x_bits);
    }
 
+DL_Group_Source DL_Group::source() const
+   {
+   return data().source();
+   }
+
 /*
 * DER encode the parameters
 */
@@ -586,12 +604,21 @@ std::string DL_Group::PEM_encode(Format format) const
 
 DL_Group::DL_Group(const uint8_t ber[], size_t ber_len, Format format)
    {
-   m_data = BER_decode_DL_group(ber, ber_len, format);
+   m_data = BER_decode_DL_group(ber, ber_len, format, DL_Group_Source::ExternalSource);
    }
 
 void DL_Group::BER_decode(const std::vector<uint8_t>& ber, Format format)
    {
-   m_data = BER_decode_DL_group(ber.data(), ber.size(), format);
+   m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource);
+   }
+
+//static
+DL_Group DL_Group::DL_Group_from_PEM(const std::string& pem)
+   {
+   std::string label;
+   const std::vector<uint8_t> ber = unlock(PEM_Code::decode(pem, label));
+   Format format = pem_label_to_dl_format(label);
+   return DL_Group(ber, format);
    }
 
 /*
@@ -603,7 +630,7 @@ void DL_Group::PEM_decode(const std::string& pem)
    const std::vector<uint8_t> ber = unlock(PEM_Code::decode(pem, label));
    Format format = pem_label_to_dl_format(label);
 
-   m_data = BER_decode_DL_group(ber.data(), ber.size(), format);
+   m_data = BER_decode_DL_group(ber.data(), ber.size(), format, DL_Group_Source::ExternalSource);
    }
 
 //static
diff --git a/src/lib/pubkey/dl_group/dl_group.h b/src/lib/pubkey/dl_group/dl_group.h
index 5ec0bfe9d..98ce7a7ad 100644
--- a/src/lib/pubkey/dl_group/dl_group.h
+++ b/src/lib/pubkey/dl_group/dl_group.h
@@ -15,6 +15,12 @@ namespace Botan {
 class Montgomery_Params;
 class DL_Group_Data;
 
+enum class DL_Group_Source {
+   Builtin,
+   RandomlyGenerated,
+   ExternalSource,
+};
+
 /**
 * This class represents discrete logarithm groups. It holds a prime
 * modulus p, a generator g, and (optionally) a prime q which is a
@@ -51,13 +57,19 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
 
       /**
       * Construct a DL group that is registered in the configuration.
-      * @param name the name that is configured in the global configuration
-      * for the desired group. If no configuration file is specified,
-      * the default values from the file policy.cpp will be used. For instance,
-      * use "modp/ietf/3072".
+      * @param name the name of the group, for example "modp/ietf/3072"
+      *
+      * @warning This constructor also accepts PEM inputs. This behavior is
+      * deprecated and will be removed in a future major release. Instead
+      * use DL_Group_from_PEM function
       */
       explicit DL_Group(const std::string& name);
 
+      /*
+      * Read a PEM representation
+      */
+      static DL_Group DL_Group_from_PEM(const std::string& pem);
+
       /**
       * Create a new group randomly.
       * @param rng the random number generator to use
@@ -109,7 +121,7 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
       * Decode a BER-encoded DL group param
       */
       template<typename Alloc>
-      DL_Group(const std::vector<uint8_t, Alloc>& ber, Format format) :
+         DL_Group(const std::vector<uint8_t, Alloc>& ber, Format format) :
          DL_Group(ber.data(), ber.size(), format) {}
 
       /**
@@ -299,6 +311,8 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
       * Decode a DER/BER encoded group into this instance.
       * @param ber a vector containing the DER/BER encoded group
       * @param format the format of the encoded group
+      *
+      * @warning avoid this. Instead use the DL_Group constructor
       */
       void BER_decode(const std::vector<uint8_t>& ber, Format format);
 
@@ -306,7 +320,9 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
       * Decode a PEM encoded group into this instance.
       * @param pem the PEM encoding of the group
       */
-      void PEM_decode(const std::string& pem);
+      void BOTAN_DEPRECATED("Use DL_Group_from_PEM") PEM_decode(const std::string& pem);
+
+      DL_Group_Source source() const;
 
       /**
       * Return PEM representation of named DL group
@@ -328,7 +344,9 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
                                                                const char* g_str);
 
       static std::shared_ptr<DL_Group_Data>
-         BER_decode_DL_group(const uint8_t data[], size_t data_len, DL_Group::Format format);
+         BER_decode_DL_group(const uint8_t data[], size_t data_len,
+                             DL_Group::Format format,
+                             DL_Group_Source source);
 
       const DL_Group_Data& data() const;
       std::shared_ptr<DL_Group_Data> m_data;
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index 801f24bf3..bb60bacf7 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -32,7 +32,8 @@ class EC_Group_Data final
                     const BigInt& g_y,
                     const BigInt& order,
                     const BigInt& cofactor,
-                    const OID& oid) :
+                    const OID& oid,
+                    EC_Group_Source source) :
          m_curve(p, a, b),
          m_base_point(m_curve, g_x, g_y),
          m_g_x(g_x),
@@ -45,7 +46,8 @@ class EC_Group_Data final
          m_p_bits(p.bits()),
          m_order_bits(order.bits()),
          m_a_is_minus_3(a == p - 3),
-         m_a_is_zero(a.is_zero())
+         m_a_is_zero(a.is_zero()),
+         m_source(source)
          {
          }
 
@@ -118,6 +120,8 @@ class EC_Group_Data final
          return m_base_mult.mul(k, rng, m_order, ws);
          }
 
+      EC_Group_Source source() const { return m_source; }
+
    private:
       CurveGFp m_curve;
       PointGFp m_base_point;
@@ -133,6 +137,7 @@ class EC_Group_Data final
       size_t m_order_bits;
       bool m_a_is_minus_3;
       bool m_a_is_zero;
+      EC_Group_Source m_source;
    };
 
 class EC_Group_Data_Map final
@@ -178,7 +183,8 @@ class EC_Group_Data_Map final
                                                       const BigInt& g_y,
                                                       const BigInt& order,
                                                       const BigInt& cofactor,
-                                                      const OID& oid)
+                                                      const OID& oid,
+                                                      EC_Group_Source source)
          {
          lock_guard_type<mutex_type> lock(m_mutex);
 
@@ -235,7 +241,7 @@ class EC_Group_Data_Map final
 
          // Not found or no OID, add data and return
          std::shared_ptr<EC_Group_Data> d =
-            std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid);
+            std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
 
          m_registered_curves.push_back(d);
          return d;
@@ -283,11 +289,12 @@ EC_Group::load_EC_group_info(const char* p_str,
    const BigInt order(order_str);
    const BigInt cofactor(1); // implicit
 
-   return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid);
+   return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, EC_Group_Source::Builtin);
    }
 
 //static
-std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len)
+std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len,
+                                                             EC_Group_Source source)
    {
    BER_Decoder ber(bits, len);
    BER_Object obj = ber.get_next_object();
@@ -344,7 +351,8 @@ std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[
 
       std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b);
 
-      return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID());
+      return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second,
+                                              order, cofactor, OID(), source);
       }
    else
       {
@@ -389,7 +397,7 @@ EC_Group::EC_Group(const std::string& str)
          {
          // OK try it as PEM ...
          secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS");
-         this->m_data = BER_decode_EC_group(ber.data(), ber.size());
+         this->m_data = BER_decode_EC_group(ber.data(), ber.size(), EC_Group_Source::ExternalSource);
          }
       }
 
@@ -397,6 +405,13 @@ EC_Group::EC_Group(const std::string& str)
       throw Invalid_Argument("Unknown ECC group '" + str + "'");
    }
 
+//static
+EC_Group EC_Group::EC_Group_from_PEM(const std::string& pem)
+   {
+   const auto ber = PEM_Code::decode_check_label(pem, "EC PARAMETERS");
+   return EC_Group(ber.data(), ber.size());
+   }
+
 //static
 std::string EC_Group::PEM_for_named_group(const std::string& name)
    {
@@ -420,12 +435,13 @@ EC_Group::EC_Group(const BigInt& p,
                    const BigInt& cofactor,
                    const OID& oid)
    {
-   m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid);
+   m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid,
+                                             EC_Group_Source::ExternalSource);
    }
 
-EC_Group::EC_Group(const std::vector<uint8_t>& ber)
+EC_Group::EC_Group(const uint8_t ber[], size_t ber_len)
    {
-   m_data = BER_decode_EC_group(ber.data(), ber.size());
+   m_data = BER_decode_EC_group(ber, ber_len, EC_Group_Source::ExternalSource);
    }
 
 const EC_Group_Data& EC_Group::data() const
@@ -540,6 +556,11 @@ const OID& EC_Group::get_curve_oid() const
    return data().oid();
    }
 
+EC_Group_Source EC_Group::source() const
+   {
+   return data().source();
+   }
+
 size_t EC_Group::point_size(PointGFp::Compression_Type format) const
    {
    // Hybrid and standard format are (x,y), compressed is y, +1 format byte
@@ -701,29 +722,37 @@ bool EC_Group::verify_public_element(const PointGFp& point) const
    }
 
 bool EC_Group::verify_group(RandomNumberGenerator& rng,
-                            bool) const
+                            bool strong) const
    {
+   const bool is_builtin = source() == EC_Group_Source::Builtin;
+
+   if(is_builtin && !strong)
+      return true;
+
    const BigInt& p = get_p();
    const BigInt& a = get_a();
    const BigInt& b = get_b();
    const BigInt& order = get_order();
    const PointGFp& base_point = get_base_point();
 
+   if(p <= 3 || order <= 0)
+      return false;
    if(a < 0 || a >= p)
       return false;
    if(b <= 0 || b >= p)
       return false;
-   if(order <= 0)
-      return false;
+
+   const size_t test_prob = 128;
+   const bool is_randomly_generated = is_builtin;
 
    //check if field modulus is prime
-   if(!is_prime(p, rng, 128))
+   if(!is_prime(p, rng, test_prob, is_randomly_generated))
       {
       return false;
       }
 
    //check if order is prime
-   if(!is_prime(order, rng, 128))
+   if(!is_prime(order, rng, test_prob, is_randomly_generated))
       {
       return false;
       }
diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h
index 976afd99d..ec06624e2 100644
--- a/src/lib/pubkey/ec_group/ec_group.h
+++ b/src/lib/pubkey/ec_group/ec_group.h
@@ -26,6 +26,11 @@ enum EC_Group_Encoding {
    EC_DOMPAR_ENC_OID = 2
 };
 
+enum class EC_Group_Source {
+   Builtin,
+   ExternalSource,
+};
+
 class CurveGFp;
 
 class EC_Group_Data;
@@ -83,9 +88,14 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
 
       /**
       * Decode a BER encoded ECC domain parameter set
-      * @param ber_encoding the bytes of the BER encoding
+      * @param ber the bytes of the BER encoding
+      * @param ber_len the length of ber
       */
-      explicit EC_Group(const std::vector<uint8_t>& ber_encoding);
+      explicit EC_Group(const uint8_t ber[], size_t ber_len);
+
+      template<typename Alloc>
+         EC_Group(const std::vector<uint8_t, Alloc>& ber) :
+         EC_Group(ber.data(), ber.size()) {}
 
       /**
       * Create an EC domain by OID (or throw if unknown)
@@ -97,9 +107,14 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
       * Create an EC domain from PEM encoding (as from PEM_encode), or
       * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7")
       * @param pem_or_oid PEM-encoded data, or an OID
+
+      * @warning Support for PEM in this function is deprecated. Use
+      * EC_Group_from_PEM
       */
       explicit EC_Group(const std::string& pem_or_oid);
 
+      static EC_Group EC_Group_from_PEM(const std::string& pem);
+
       /**
       * Create an uninitialized EC_Group
       */
@@ -329,6 +344,8 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
 
       bool operator==(const EC_Group& other) const;
 
+      EC_Group_Source source() const;
+
       /**
       * Return PEM representation of named EC group
       * Deprecated: Use EC_Group(name).PEM_encode() if this is needed
@@ -350,7 +367,8 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
    private:
       static EC_Group_Data_Map& ec_group_data();
 
-      static std::shared_ptr<EC_Group_Data> BER_decode_EC_group(const uint8_t bits[], size_t len);
+      static std::shared_ptr<EC_Group_Data> BER_decode_EC_group(const uint8_t bits[], size_t len,
+                                                                EC_Group_Source source);
 
       static std::shared_ptr<EC_Group_Data>
          load_EC_group_info(const char* p,


Test patch:
diff --git a/src/tests/test_dl_group.cpp b/src/tests/test_dl_group.cpp
index 3a0c93e75..ed0e4168a 100644
--- a/src/tests/test_dl_group.cpp
+++ b/src/tests/test_dl_group.cpp
@@ -215,6 +215,8 @@ class DL_Named_Group_Tests final : public Test
             // 8192 bit ~~ 2**202 strength
             result.confirm("Plausible strength", strength >= 80 && strength < 210);
 
+            result.confirm("Expected source", group.source() == Botan::DL_Group_Source::Builtin);
+
             if(name.find("modp/srp/") == std::string::npos)
                {
                result.test_ne("DL_Group q is set", group.get_q(), 0);
@@ -224,9 +226,9 @@ class DL_Named_Group_Tests final : public Test
                result.test_eq("DL_Group q is not set for SRP groups", group.get_q(), 0);
                }
 
-            if(group.p_bits() < 2048 || Test::run_long_tests())
+            if(group.p_bits() <= 1536 || Test::run_long_tests())
                {
-               result.test_eq(name + " verifies", group.verify_group(Test::rng(), false), true);
+               result.test_eq(name + " strong verifies", group.verify_group(Test::rng(), true), true);
                }
 
             }