Skip to content

Commit

Permalink
Merge pull request #4218 from randombit/jack/pcurves-p224
Browse files Browse the repository at this point in the history
Add pcurves P-224
  • Loading branch information
randombit authored Aug 9, 2024
2 parents c319901 + 0cb7102 commit 8b4905e
Show file tree
Hide file tree
Showing 11 changed files with 494 additions and 17 deletions.
14 changes: 14 additions & 0 deletions src/lib/math/pcurves/pcurves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp192r1() {
}
#endif

#if !defined(BOTAN_HAS_PCURVES_SECP224R1)
//static
std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp224r1() {
return nullptr;
}
#endif

#if !defined(BOTAN_HAS_PCURVES_SECP256R1)
//static
std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp256r1() {
Expand Down Expand Up @@ -95,6 +102,8 @@ std::shared_ptr<const PrimeOrderCurve> PrimeOrderCurve::from_id(PrimeOrderCurveI
switch(id.code()) {
case PrimeOrderCurveId::secp192r1:
return PCurveInstance::secp192r1();
case PrimeOrderCurveId::secp224r1:
return PCurveInstance::secp224r1();
case PrimeOrderCurveId::secp256r1:
return PCurveInstance::secp256r1();
case PrimeOrderCurveId::secp384r1:
Expand Down Expand Up @@ -122,6 +131,7 @@ std::shared_ptr<const PrimeOrderCurve> PrimeOrderCurve::from_id(PrimeOrderCurveI
std::vector<PrimeOrderCurveId> PrimeOrderCurveId::all() {
return {
PrimeOrderCurveId::secp192r1,
PrimeOrderCurveId::secp224r1,
PrimeOrderCurveId::secp256r1,
PrimeOrderCurveId::secp384r1,
PrimeOrderCurveId::secp521r1,
Expand All @@ -139,6 +149,8 @@ std::string PrimeOrderCurveId::to_string() const {
switch(this->code()) {
case PrimeOrderCurveId::secp192r1:
return "secp192r1";
case PrimeOrderCurveId::secp224r1:
return "secp224r1";
case PrimeOrderCurveId::secp256r1:
return "secp256r1";
case PrimeOrderCurveId::secp384r1:
Expand Down Expand Up @@ -168,6 +180,8 @@ std::string PrimeOrderCurveId::to_string() const {
std::optional<PrimeOrderCurveId> PrimeOrderCurveId::from_string(std::string_view name) {
if(name == "secp192r1") {
return PCurve::PrimeOrderCurveId::secp192r1;
} else if(name == "secp224r1") {
return PCurve::PrimeOrderCurveId::secp224r1;
} else if(name == "secp256r1") {
return PCurve::PrimeOrderCurveId::secp256r1;
} else if(name == "secp384r1") {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/math/pcurves/pcurves_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class BOTAN_TEST_API PrimeOrderCurveId final {
enum class Code : uint8_t {
/// secp192r1 aka P-192
secp192r1,
/// secp224r1 aka P-224
secp224r1,
/// secp256r1 aka P-256
secp256r1,
/// secp384r1 aka P-384
Expand Down
62 changes: 49 additions & 13 deletions src/lib/math/pcurves/pcurves_impl/pcurves_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ class IntMod final {
typedef typename Rep::W W;

static constexpr auto P_MINUS_2 = p_minus<2>(P);
static constexpr auto P_PLUS_1_OVER_4 = p_plus_1_over_4(P);

public:
static constexpr size_t BITS = count_bits(P);
Expand Down Expand Up @@ -291,17 +290,54 @@ class IntMod final {
constexpr Self invert() const { return pow_vartime(Self::P_MINUS_2); }

/**
* Return the modular square root, or zero if no root exists
*
* Current impl assumes p == 3 (mod 4)
* Return the modular square root if it exists
*/
constexpr std::pair<Self, CT::Choice> sqrt() const
requires(Self::P_MOD_4 == 3)
{
auto z = pow_vartime(Self::P_PLUS_1_OVER_4);
const CT::Choice correct = (z.square() == *this);
Self::conditional_assign(z, !correct, Self::zero());
return {z, correct};
constexpr std::pair<Self, CT::Choice> sqrt() const {
if constexpr(Self::P_MOD_4 == 3) {
constexpr auto P_PLUS_1_OVER_4 = p_plus_1_over_4(P);
auto z = pow_vartime(P_PLUS_1_OVER_4);
const CT::Choice correct = (z.square() == *this);
Self::conditional_assign(z, !correct, Self::zero());
return {z, correct};
} else {
// Shanks-Tonelli, following I.4 in RFC 9380

/*
Constants:
1. c1, the largest integer such that 2^c1 divides q - 1.
2. c2 = (q - 1) / (2^c1) # Integer arithmetic
3. c3 = (c2 - 1) / 2 # Integer arithmetic
4. c4, a non-square value in F
5. c5 = c4^c2 in F
*/
constexpr auto C1_C2 = shanks_tonelli_c1c2(Self::P);
constexpr std::array<W, N> C3 = shanks_tonelli_c3(C1_C2.second);
constexpr std::array<W, N> P_MINUS_1_OVER_2 = p_minus_1_over_2(Self::P);
constexpr Self C4 = shanks_tonelli_c4<Self>(P_MINUS_1_OVER_2);
constexpr Self C5 = C4.pow_vartime(C1_C2.second);

const Self& x = (*this);

auto z = x.pow_vartime(C3);
auto t = z.square();
t *= x;
z *= x;
auto b = t;
auto c = C5;

for(size_t i = C1_C2.first; i >= 2; i--) {
b.square_n(i - 2);
const auto e = b.is_one();
Self::conditional_assign(z, !e, z * c);
c.square_n(1);
Self::conditional_assign(t, !e, t * c);
b = t;
}

const CT::Choice correct = (z.square() == *this);
Self::conditional_assign(z, !correct, Self::zero());
return {z, correct};
}
}

constexpr CT::Choice operator==(const Self& other) const {
Expand Down Expand Up @@ -349,7 +385,7 @@ class IntMod final {
}

// Returns nullopt if the input is an encoding greater than or equal P
constexpr static std::optional<Self> deserialize(std::span<const uint8_t> bytes) {
static std::optional<Self> deserialize(std::span<const uint8_t> bytes) {
// We could allow either short inputs or longer zero padded
// inputs here, however it seems best to avoid non-canonical
// representations unless required
Expand Down Expand Up @@ -522,7 +558,7 @@ class AffineCurvePoint {

static constexpr FieldElement x3_ax_b(const FieldElement& x) { return (x.square() + Self::A) * x + Self::B; }

static constexpr std::optional<Self> deserialize(std::span<const uint8_t> bytes) {
static std::optional<Self> deserialize(std::span<const uint8_t> bytes) {
if(bytes.size() == Self::BYTES) {
if(bytes[0] != 0x04) {
return {};
Expand Down
1 change: 0 additions & 1 deletion src/lib/math/pcurves/pcurves_impl/pcurves_solinas.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ class SolinasAccum {
}

constexpr W final_carry(int64_t C) {
BOTAN_DEBUG_ASSERT(m_idx == N32);
m_S += C;
BOTAN_DEBUG_ASSERT(m_S >= 0);
return static_cast<W>(m_S);
Expand Down
52 changes: 52 additions & 0 deletions src/lib/math/pcurves/pcurves_impl/pcurves_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,58 @@ inline consteval std::array<W, N> p_div_2_plus_1(const std::array<W, N>& p) {
return r;
}

template <WordType W, size_t N>
inline consteval std::pair<size_t, std::array<W, N>> shanks_tonelli_c1c2(const std::array<W, N>& p) {
size_t c1 = 0;
auto c2 = p;

// This assumes p % 2 == 1
shift_right<1>(c2);
c1++;

for(;;) {
// If we found another one bit past the first, stop
if(c2[0] % 2 == 1) {
break;
}
shift_right<1>(c2);
c1++;
}

std::reverse(c2.begin(), c2.end());
return {c1, c2};
}

template <WordType W, size_t N>
inline consteval std::array<W, N> shanks_tonelli_c3(const std::array<W, N>& c2) {
auto c3 = c2;
std::reverse(c3.begin(), c3.end());
shift_right<1>(c3);
std::reverse(c3.begin(), c3.end());
return c3;
}

template <typename Z, WordType W, size_t N>
consteval auto shanks_tonelli_c4(const std::array<W, N>& p_minus_1_over_2) -> Z {
const auto one = Z::one();

// This is a silly performance hack; the first non-quadratic root in P-224
// is 11 so if we start the search there we save a little time.
auto z = Z::from_word(11);

for(;;) {
auto c = z.pow_vartime(p_minus_1_over_2);

auto is_square = c.is_zero() || c.is_one();

if(!is_square.as_bool()) {
return z;
}

z = z + one;
}
}

template <WordType W, size_t N>
inline consteval size_t count_bits(const std::array<W, N>& p) {
auto get_bit = [&](size_t i) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/math/pcurves/pcurves_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class PCurveInstance final {

static std::shared_ptr<const PrimeOrderCurve> secp192r1();

static std::shared_ptr<const PrimeOrderCurve> secp224r1();

static std::shared_ptr<const PrimeOrderCurve> secp256r1();

static std::shared_ptr<const PrimeOrderCurve> secp384r1();
Expand Down
13 changes: 13 additions & 0 deletions src/lib/math/pcurves/pcurves_secp224r1/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<defines>
PCURVES_SECP224R1 -> 20240716
</defines>

<module_info>
name -> "PCurve secp224r1"
brief -> "secp224r1"
type -> "Internal"
</module_info>

<requires>
pcurves_impl
</requires>
Loading

0 comments on commit 8b4905e

Please sign in to comment.