/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/pcurves_instance.h>

#include <botan/internal/pcurves_wrap.h>

namespace Botan::PCurve {

namespace {

namespace numsp512d1 {

template <typename Params>
class Numsp512d1Rep final {
   public:
      static constexpr auto P = Params::P;
      static constexpr size_t N = Params::N;
      typedef typename Params::W W;

      static constexpr W C = 569;

      constexpr static std::array<W, N> one() { return std::array<W, N>{1}; }

      constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) {
         return redc_crandall<W, N, C>(std::span{z});
      }

      constexpr static std::array<W, N> to_rep(const std::array<W, N>& x) { return x; }

      constexpr static std::array<W, N> wide_to_rep(const std::array<W, 2 * N>& x) { return redc(x); }

      constexpr static std::array<W, N> from_rep(const std::array<W, N>& z) { return z; }
};

// clang-format off

class Params final : public EllipticCurveParameters<
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",
   "1D99B",
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B3CA4FB94E7831B4FC258ED97D0BDC63B568B36607CD243CE153F390433555D",
   "2",
   "1C282EB23327F9711952C250EA61AD53FCC13031CF6DD336E0B9328433AFBDD8CC5A1C1F0C716FDC724DDE537C2B0ADB00BB3D08DC83755B205CC30D7F83CF28",
   -4> {
};

// clang-format on

class Curve final : public EllipticCurve<Params, Numsp512d1Rep> {
   public:
      static constexpr FieldElement fe_invert2(const FieldElement& x) {
         // Generated by https://github.com/mmcloughlin/addchain
         auto z = x.square();
         z *= x;
         z = z.square();
         z *= x;
         auto t0 = z;
         t0.square_n(3);
         t0 *= z;
         t0.square_n(3);
         auto t1 = t0 * z;
         t0 = t1;
         t0.square_n(9);
         t0 *= t1;
         t0.square_n(3);
         t0 *= z;
         auto t2 = t0;
         t2.square_n(9);
         t1 *= t2;
         t2 = t1;
         t2.square_n(30);
         t1 *= t2;
         t2 = t1;
         t2.square_n(60);
         t1 *= t2;
         t2 = t1;
         t2.square_n(120);
         t1 *= t2;
         t2 = t1;
         t2.square_n(240);
         t1 *= t2;
         t1.square_n(21);
         t0 *= t1;
         t0 = t0.square();
         t0 *= x;
         t0.square_n(4);
         z *= t0;
         z.square_n(4);
         z *= x;
         z.square_n(2);
         return z;
      }

      static constexpr FieldElement fe_sqrt(const FieldElement& x) {
         // Generated by https://github.com/mmcloughlin/addchain
         auto z = x.square();
         z *= x;
         z = z.square();
         z *= x;
         auto t0 = z;
         t0.square_n(3);
         t0 *= z;
         t0.square_n(3);
         auto t1 = t0 * z;
         t0 = t1;
         t0.square_n(9);
         t0 *= t1;
         t0.square_n(3);
         t0 *= z;
         auto t2 = t0;
         t2.square_n(9);
         t1 *= t2;
         t2 = t1;
         t2.square_n(30);
         t1 *= t2;
         t2 = t1;
         t2.square_n(60);
         t1 *= t2;
         t2 = t1;
         t2.square_n(120);
         t1 *= t2;
         t2 = t1;
         t2.square_n(240);
         t1 *= t2;
         t1.square_n(21);
         t0 *= t1;
         t0 = t0.square();
         t0 *= x;
         t0.square_n(4);
         z *= t0;
         z.square_n(3);
         z *= x;
         z = z.square();
         return z;
      }
};

}  // namespace numsp512d1

}  // namespace

std::shared_ptr<const PrimeOrderCurve> PCurveInstance::numsp512d1() {
   return PrimeOrderCurveImpl<numsp512d1::Curve>::instance();
}

}  // namespace Botan::PCurve
