<commit_before>/*
* (C) 2007 <NAME>
*     2007 <NAME>
*     2009,2015 <NAME>
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_ECC_GROUP)
   #include <botan/bigint.h>
   #include <botan/numthry.h>
   #include <botan/curve_nistp.h>
   #include <botan/pk_keys.h>
   #include <botan/point_gfp.h>
   #include <botan/ec_group.h>
   #include <botan/reducer.h>
   #include <botan/hex.h>
   #include <botan/data_src.h>
   #include <botan/x509_key.h>
#endif

namespace Botan_Tests {

namespace {

#if defined(BOTAN_HAS_ECC_GROUP)

Botan::BigInt test_integer(Botan::RandomNumberGenerator& rng, size_t bits, BigInt max)
   {
   /*
   Produces integers with long runs of ones and zeros, for testing for
   carry handling problems.
   */
   Botan::BigInt x = 0;

   auto flip_prob = [](size_t i) -> double
      {
      if(i % 64 == 0)
         {
         return .5;
         }
      if(i % 32 == 0)
         {
         return .4;
         }
      if(i % 8 == 0)
         {
         return .05;
         }
      return .01;
      };

   bool active = rng.next_byte() % 2;
   for(size_t i = 0; i != bits; ++i)
      {
      x <<= 1;
      x += static_cast<int>(active);

      const double prob = flip_prob(i);
      const double sample = double(rng.next_byte() % 100) / 100.0; // biased

      if(sample < prob)
         {
         active = !active;
         }
      }

   if(max > 0)
      {
      while(x >= max)
         {
         const size_t b = x.bits() - 1;
         BOTAN_ASSERT(x.get_bit(b) == true, "Set");
         x.clear_bit(b);
         }
      }

   return x;
   }

Botan::PointGFp create_random_point(Botan::RandomNumberGenerator& rng,
                                    const Botan::EC_Group& group)
   {
   const Botan::BigInt& p = group.get_p();

   Botan::Modular_Reducer mod_p(p);

   while(true)
      {
      const Botan::BigInt x = Botan::BigInt::random_integer(rng, 1, p);
      const Botan::BigInt x3 = mod_p.multiply(x, mod_p.square(x));
      const Botan::BigInt ax = mod_p.multiply(group.get_a(), x);
      const Botan::BigInt y = mod_p.reduce(x3 + ax + group.get_b());
      const Botan::BigInt sqrt_y = ressol(y, p);

      if(sqrt_y > 1)
         {
         BOTAN_ASSERT_EQUAL(mod_p.square(sqrt_y), y, "Square root is correct");
         Botan::PointGFp point = group.point(x, sqrt_y);
         return point;
         }
      }
   }

class ECC_Randomized_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override;
   };

std::vector<Test::Result> ECC_Randomized_Tests::run()
   {
   std::vector<Test::Result> results;
   std::set<std::string> named_groups = Botan::EC_Group::known_named_groups();
   for(auto const& group_name : named_groups)
      {
      Test::Result result("ECC randomized " + group_name);

      result.start_timer();

      Botan::EC_Group group(group_name);

      const Botan::PointGFp& base_point = group.get_base_point();
      const Botan::BigInt& group_order = group.get_order();

      const Botan::PointGFp inf = base_point * group_order;
      result.test_eq("infinite order correct", inf.is_zero(), true);
      result.test_eq("infinity on the curve", inf.on_the_curve(), true);

      std::vector<Botan::BigInt> blind_ws;

      try
         {
         const size_t trials = (Test::run_long_tests() ? 10 : 3);
         for(size_t i = 0; i < trials; ++i)
            {
            const size_t w = 1 + (Test::rng().next_byte() % 8);

            Botan::PointGFp_Blinded_Multiplier blinded(base_point, w);

            const Botan::BigInt a = Botan::BigInt::random_integer(Test::rng(), 2, group_order);
            const Botan::BigInt b = Botan::BigInt::random_integer(Test::rng(), 2, group_order);
            const Botan::BigInt c = a + b;

            const Botan::PointGFp P = base_point * a;
            const Botan::PointGFp Q = base_point * b;
            const Botan::PointGFp R = base_point * c;

            const Botan::PointGFp P1 = blinded.mul(a, group_order, Test::rng(), blind_ws);
            const Botan::PointGFp Q1 = blinded.mul(b, group_order, Test::rng(), blind_ws);
            const Botan::PointGFp R1 = blinded.mul(c, group_order, Test::rng(), blind_ws);

            const Botan::PointGFp A1 = P + Q;
            const Botan::PointGFp A2 = Q + P;

            result.test_eq("p + q", A1, R);
            result.test_eq("q + p", A2, R);

            result.test_eq("p on the curve", P.on_the_curve(), true);
            result.test_eq("q on the curve", Q.on_the_curve(), true);
            result.test_eq("r on the curve", R.on_the_curve(), true);

            result.test_eq("P1", P1, P);
            result.test_eq("Q1", Q1, Q);
            result.test_eq("R1", R1, R);
            }
         }
      catch(std::exception& e)
         {
         result.test_failure(group_name, e.what());
         }
      result.end_timer();
      results.push_back(result);
      }

   return results;
   }

BOTAN_REGISTER_TEST("ecc_randomized", ECC_Randomized_Tests);

class NIST_Curve_Reduction_Tests final : public Test
   {
   public:
      typedef std::function<void (Botan::BigInt&, Botan::secure_vector<Botan::word>&)> reducer_fn;
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32)
         results.push_back(random_redc_test(
	    "P-384",
	    Botan::prime_p384(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p384(p, ws);
		}));
         results.push_back(random_redc_test(
	    "P-256",
	    Botan::prime_p256(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p256(p, ws);
		}));
         results.push_back(random_redc_test(
	    "P-224",
	    Botan::prime_p224(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p224(p, ws);<commit_msg>Add comment explaining why we are using these useless lambdas<commit_after>/*
* (C) 2007 <NAME>
*     2007 <NAME>
*     2009,2015 <NAME>
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include "tests.h"

#if defined(BOTAN_HAS_ECC_GROUP)
   #include <botan/bigint.h>
   #include <botan/numthry.h>
   #include <botan/curve_nistp.h>
   #include <botan/pk_keys.h>
   #include <botan/point_gfp.h>
   #include <botan/ec_group.h>
   #include <botan/reducer.h>
   #include <botan/hex.h>
   #include <botan/data_src.h>
   #include <botan/x509_key.h>
#endif

namespace Botan_Tests {

namespace {

#if defined(BOTAN_HAS_ECC_GROUP)

Botan::BigInt test_integer(Botan::RandomNumberGenerator& rng, size_t bits, BigInt max)
   {
   /*
   Produces integers with long runs of ones and zeros, for testing for
   carry handling problems.
   */
   Botan::BigInt x = 0;

   auto flip_prob = [](size_t i) -> double
      {
      if(i % 64 == 0)
         {
         return .5;
         }
      if(i % 32 == 0)
         {
         return .4;
         }
      if(i % 8 == 0)
         {
         return .05;
         }
      return .01;
      };

   bool active = rng.next_byte() % 2;
   for(size_t i = 0; i != bits; ++i)
      {
      x <<= 1;
      x += static_cast<int>(active);

      const double prob = flip_prob(i);
      const double sample = double(rng.next_byte() % 100) / 100.0; // biased

      if(sample < prob)
         {
         active = !active;
         }
      }

   if(max > 0)
      {
      while(x >= max)
         {
         const size_t b = x.bits() - 1;
         BOTAN_ASSERT(x.get_bit(b) == true, "Set");
         x.clear_bit(b);
         }
      }

   return x;
   }

Botan::PointGFp create_random_point(Botan::RandomNumberGenerator& rng,
                                    const Botan::EC_Group& group)
   {
   const Botan::BigInt& p = group.get_p();

   Botan::Modular_Reducer mod_p(p);

   while(true)
      {
      const Botan::BigInt x = Botan::BigInt::random_integer(rng, 1, p);
      const Botan::BigInt x3 = mod_p.multiply(x, mod_p.square(x));
      const Botan::BigInt ax = mod_p.multiply(group.get_a(), x);
      const Botan::BigInt y = mod_p.reduce(x3 + ax + group.get_b());
      const Botan::BigInt sqrt_y = ressol(y, p);

      if(sqrt_y > 1)
         {
         BOTAN_ASSERT_EQUAL(mod_p.square(sqrt_y), y, "Square root is correct");
         Botan::PointGFp point = group.point(x, sqrt_y);
         return point;
         }
      }
   }

class ECC_Randomized_Tests final : public Test
   {
   public:
      std::vector<Test::Result> run() override;
   };

std::vector<Test::Result> ECC_Randomized_Tests::run()
   {
   std::vector<Test::Result> results;
   std::set<std::string> named_groups = Botan::EC_Group::known_named_groups();
   for(auto const& group_name : named_groups)
      {
      Test::Result result("ECC randomized " + group_name);

      result.start_timer();

      Botan::EC_Group group(group_name);

      const Botan::PointGFp& base_point = group.get_base_point();
      const Botan::BigInt& group_order = group.get_order();

      const Botan::PointGFp inf = base_point * group_order;
      result.test_eq("infinite order correct", inf.is_zero(), true);
      result.test_eq("infinity on the curve", inf.on_the_curve(), true);

      std::vector<Botan::BigInt> blind_ws;

      try
         {
         const size_t trials = (Test::run_long_tests() ? 10 : 3);
         for(size_t i = 0; i < trials; ++i)
            {
            const size_t w = 1 + (Test::rng().next_byte() % 8);

            Botan::PointGFp_Blinded_Multiplier blinded(base_point, w);

            const Botan::BigInt a = Botan::BigInt::random_integer(Test::rng(), 2, group_order);
            const Botan::BigInt b = Botan::BigInt::random_integer(Test::rng(), 2, group_order);
            const Botan::BigInt c = a + b;

            const Botan::PointGFp P = base_point * a;
            const Botan::PointGFp Q = base_point * b;
            const Botan::PointGFp R = base_point * c;

            const Botan::PointGFp P1 = blinded.mul(a, group_order, Test::rng(), blind_ws);
            const Botan::PointGFp Q1 = blinded.mul(b, group_order, Test::rng(), blind_ws);
            const Botan::PointGFp R1 = blinded.mul(c, group_order, Test::rng(), blind_ws);

            const Botan::PointGFp A1 = P + Q;
            const Botan::PointGFp A2 = Q + P;

            result.test_eq("p + q", A1, R);
            result.test_eq("q + p", A2, R);

            result.test_eq("p on the curve", P.on_the_curve(), true);
            result.test_eq("q on the curve", Q.on_the_curve(), true);
            result.test_eq("r on the curve", R.on_the_curve(), true);

            result.test_eq("P1", P1, P);
            result.test_eq("Q1", Q1, Q);
            result.test_eq("R1", R1, R);
            }
         }
      catch(std::exception& e)
         {
         result.test_failure(group_name, e.what());
         }
      result.end_timer();
      results.push_back(result);
      }

   return results;
   }

BOTAN_REGISTER_TEST("ecc_randomized", ECC_Randomized_Tests);

class NIST_Curve_Reduction_Tests final : public Test
   {
   public:
      typedef std::function<void (Botan::BigInt&, Botan::secure_vector<Botan::word>&)> reducer_fn;
      std::vector<Test::Result> run() override
         {
         std::vector<Test::Result> results;

         // Using lambdas here to avoid strange UbSan warning (#1370)

#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32)
         results.push_back(random_redc_test(
	    "P-384",
	    Botan::prime_p384(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p384(p, ws);
		}));
         results.push_back(random_redc_test(
	    "P-256",
	    Botan::prime_p256(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p256(p, ws);
		}));
         results.push_back(random_redc_test(
	    "P-224",
	    Botan::prime_p224(),
	    [](Botan::BigInt& p, Botan::secure_vector<Botan::word>& ws) -> void
	        {
		Botan::redc_p224(p, ws);
{'fraction_non_alphanumeric': 0.14401925790653275, 'fraction_numerical': 0.01693367643396696, 'mean_word_length': 2.413031161473088, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '624287', 'n_tokens_mistral': 4543, 'n_tokens_neox': 4279, 'n_words': 865}