Skip to content

Commit

Permalink
Add Solinas reduction for P-224 pcurves
Browse files Browse the repository at this point in the history
The speedup we get from Solinas for P-224 (around 25%) is much higher
than seen for P-192 or P-256. This may be due to the fact that unlike
P-192 and P-256, P-224 is not "Montgomery friendly", ie p' is not
equal to 1, so the Montgomery reduction is significantly more
expensive.
  • Loading branch information
randombit committed Jul 17, 2024
1 parent 384d8ab commit 5b80202
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 3 deletions.
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
89 changes: 87 additions & 2 deletions src/lib/math/pcurves/pcurves_secp224r1/pcurves_secp224r1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <botan/internal/pcurves_instance.h>

#include <botan/internal/pcurves_solinas.h>
#include <botan/internal/pcurves_wrap.h>

namespace Botan::PCurve {
Expand All @@ -14,7 +15,91 @@ namespace {

namespace secp224r1 {

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

constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) {
const int64_t X00 = get_uint32(z.data(), 0);
const int64_t X01 = get_uint32(z.data(), 1);
const int64_t X02 = get_uint32(z.data(), 2);
const int64_t X03 = get_uint32(z.data(), 3);
const int64_t X04 = get_uint32(z.data(), 4);
const int64_t X05 = get_uint32(z.data(), 5);
const int64_t X06 = get_uint32(z.data(), 6);
const int64_t X07 = get_uint32(z.data(), 7);
const int64_t X08 = get_uint32(z.data(), 8);
const int64_t X09 = get_uint32(z.data(), 9);
const int64_t X10 = get_uint32(z.data(), 10);
const int64_t X11 = get_uint32(z.data(), 11);
const int64_t X12 = get_uint32(z.data(), 12);
const int64_t X13 = get_uint32(z.data(), 13);

const int64_t S0 = 0x00000001 + X00 - X07 - X11;
const int64_t S1 = 0x00000000 + X01 - X08 - X12;
const int64_t S2 = 0x00000000 + X02 - X09 - X13;
const int64_t S3 = 0xFFFFFFFF + X03 + X07 + X11 - X10;
const int64_t S4 = 0xFFFFFFFF + X04 + X08 + X12 - X11;
const int64_t S5 = 0xFFFFFFFF + X05 + X09 + X13 - X12;
const int64_t S6 = 0xFFFFFFFF + X06 + X10 - X13;

std::array<W, N> r = {};

SolinasAccum sum(r);

sum.accum(S0);
sum.accum(S1);
sum.accum(S2);
sum.accum(S3);
sum.accum(S4);
sum.accum(S5);
sum.accum(S6);
const auto S = sum.final_carry(0);

BOTAN_DEBUG_ASSERT(S <= 2);

const auto correction = p224_mul_mod_224(S);
W borrow = bigint_sub2(r.data(), N, correction.data(), N);

bigint_cnd_add(borrow, r.data(), N, P.data(), N);

return r;
}

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

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; }

private:
// Return (i*P-224) % 2**224
//
// Assumes i is small
constexpr static std::array<W, N> p224_mul_mod_224(W i) {
static_assert(WordInfo<W>::bits == 32 || WordInfo<W>::bits == 64);

// For small i, multiples of P-224 have a simple structure so it's faster to
// compute the value directly vs a (constant time) table lookup

auto r = P;

if constexpr(WordInfo<W>::bits == 32) {
r[3] -= i;
r[0] += i;
} else {
const W i32 = i << 32;
r[1] -= i32;
r[0] += i;
}
return r;
}
};

// clang-format off
class Params final : public EllipticCurveParameters<
Expand All @@ -28,7 +113,7 @@ class Params final : public EllipticCurveParameters<

// clang-format on

class Curve final : public EllipticCurve<Params> {};
class Curve final : public EllipticCurve<Params, Secp224r1Rep> {};

} // namespace secp224r1

Expand Down

0 comments on commit 5b80202

Please sign in to comment.