Skip to content

Commit

Permalink
Merge pull request #4142 from randombit/jack/pcurves-fixes
Browse files Browse the repository at this point in the history
Pcurves fixes and additions
  • Loading branch information
randombit authored Jun 22, 2024
2 parents 18dbe56 + 13de987 commit d24c2c3
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 24 deletions.
8 changes: 7 additions & 1 deletion src/cli/speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,13 @@ class Speed final : public Command {
while(mul2_timer->under(runtime)) {
const auto scalar = curve->random_scalar(rng());
const auto scalar2 = curve->random_scalar(rng());
mul2_timer->run([&]() { return curve->mul2_vartime(*gh_tab, scalar, scalar2).to_affine(); });
mul2_timer->run([&]() -> std::optional<Botan::PCurve::PrimeOrderCurve::AffinePoint> {
if(auto pt = curve->mul2_vartime(*gh_tab, scalar, scalar2)) {
return pt->to_affine();
} else {
return {};
}
});
}

auto pt = curve->mul(g, curve->random_scalar(rng()), rng());
Expand Down
22 changes: 16 additions & 6 deletions src/lib/math/pcurves/pcurves.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,17 +317,21 @@ class BOTAN_TEST_API PrimeOrderCurve {
/// Perform 2-ary multiplication (variable time)
///
/// Compute s1*pt1 + s2*pt2 in variable time
virtual ProjectivePoint mul2_vartime(const PrecomputedMul2Table& table,
const Scalar& s1,
const Scalar& s2) const = 0;
///
/// Returns nullopt if the produced point is the point at infinity
virtual std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& table,
const Scalar& s1,
const Scalar& s2) const = 0;

/// Perform 2-ary multiplication (variable time), reducing x modulo order
///
/// Compute s1*pt1 + s2*pt2 in variable time, then extract the x coordinate
/// of the result, and reduce x modulo the group order
virtual Scalar mul2_vartime_x_mod_order(const PrecomputedMul2Table& table,
const Scalar& s1,
const Scalar& s2) const = 0;
///
/// Returns nullopt if the produced point is the point at infinity
virtual std::optional<Scalar> mul2_vartime_x_mod_order(const PrecomputedMul2Table& table,
const Scalar& s1,
const Scalar& s2) const = 0;

/// Return the standard generator
virtual AffinePoint generator() const = 0;
Expand All @@ -352,6 +356,12 @@ class BOTAN_TEST_API PrimeOrderCurve {
/// output into a scalar.
virtual Scalar scalar_from_bits_with_trunc(std::span<const uint8_t> bytes) const = 0;

/// Reduce an integer modulo the group order
///
/// The input can be at most twice the bit length of the order; if larger than this
/// nullopt is returned
virtual std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const = 0;

virtual AffinePoint point_to_affine(const ProjectivePoint& pt) const = 0;

virtual ProjectivePoint point_to_projective(const AffinePoint& pt) const = 0;
Expand Down
15 changes: 12 additions & 3 deletions src/lib/math/pcurves/pcurves_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class IntMod final {

constexpr CT::Choice is_even() const {
auto v = Rep::from_rep(m_val);
return CT::Choice::from_int(v[0] & 0x01);
return CT::Choice::from_int(0x01 ^ (v[0] & 0x01));
}

friend constexpr Self operator+(const Self& a, const Self& b) {
Expand Down Expand Up @@ -356,6 +356,16 @@ class IntMod final {
return Self(Rep::wide_to_rep(bytes_to_words<W, 2 * N, 2 * BYTES>(std::span{padded_bytes})));
}

// Reduces large input modulo the order
static constexpr std::optional<Self> from_wide_bytes_varlen(std::span<const uint8_t> bytes) {
if(8 * bytes.size() > 2 * Self::BITS) {
return {};
}
std::array<uint8_t, 2 * BYTES> padded_bytes = {};
copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
return Self(Rep::wide_to_rep(bytes_to_words<W, 2 * N, 2 * BYTES>(std::span{padded_bytes})));
}

static Self random(RandomNumberGenerator& rng) {
constexpr size_t MAX_ATTEMPTS = 1000;

Expand Down Expand Up @@ -492,8 +502,7 @@ class AffineCurvePoint {
const CT::Choice y_is_even = CT::Mask<uint8_t>::is_equal(bytes[0], 0x02).as_choice();

if(auto x = FieldElement::deserialize(bytes.subspan(1, FieldElement::BYTES))) {
const auto y2 = x3_ax_b(*x);
auto y = y2.sqrt();
auto y = x3_ax_b(*x).sqrt();
y.conditional_assign(y_is_even && !y.is_even(), y.negate());
return Self(*x, y);
}
Expand Down
39 changes: 29 additions & 10 deletions src/lib/math/pcurves/pcurves_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,32 @@ class PrimeOrderCurveImpl final : public PrimeOrderCurve {
return std::make_unique<PrecomputedMul2TableC>(from_stash(x), from_stash(y));
}

ProjectivePoint mul2_vartime(const PrecomputedMul2Table& tableb,
const Scalar& s1,
const Scalar& s2) const override {
std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& tableb,
const Scalar& s1,
const Scalar& s2) const override {
try {
const auto& table = dynamic_cast<const PrecomputedMul2TableC&>(tableb);
return stash(table.table().mul2_vartime(from_stash(s1), from_stash(s2)));
auto pt = table.table().mul2_vartime(from_stash(s1), from_stash(s2));
if(pt.is_identity().as_bool()) {
return {};
} else {
return stash(pt);
}
} catch(std::bad_cast&) {
throw Invalid_Argument("Curve mismatch");
}
}

Scalar mul2_vartime_x_mod_order(const PrecomputedMul2Table& tableb,
const Scalar& s1,
const Scalar& s2) const override {
std::optional<Scalar> mul2_vartime_x_mod_order(const PrecomputedMul2Table& tableb,
const Scalar& s1,
const Scalar& s2) const override {
try {
const auto& table = dynamic_cast<const PrecomputedMul2TableC&>(tableb);
const auto pt = table.table().mul2_vartime(from_stash(s1), from_stash(s2));
// Variable time here, so the early return is fine
if(pt.is_identity().as_bool()) {
return {};
}
std::array<uint8_t, C::FieldElement::BYTES> x_bytes;
pt.to_affine().x().serialize_to(std::span{x_bytes});
return stash(C::Scalar::from_wide_bytes(std::span<const uint8_t, C::FieldElement::BYTES>{x_bytes}));
Expand Down Expand Up @@ -132,16 +141,26 @@ class PrimeOrderCurveImpl final : public PrimeOrderCurve {

std::optional<Scalar> deserialize_scalar(std::span<const uint8_t> bytes) const override {
if(auto scalar = C::Scalar::deserialize(bytes)) {
return stash(*scalar);
} else {
return {};
if(!scalar->is_zero().as_bool()) {
return stash(*scalar);
}
}

return {};
}

Scalar scalar_from_bits_with_trunc(std::span<const uint8_t> bytes) const override {
return stash(C::Scalar::from_bits_with_trunc(bytes));
}

std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const override {
if(auto s = C::Scalar::from_wide_bytes_varlen(bytes)) {
return stash(*s);
} else {
return {};
}
}

std::optional<AffinePoint> deserialize_point(std::span<const uint8_t> bytes) const override {
if(auto pt = C::AffinePoint::deserialize(bytes)) {
return stash(*pt);
Expand Down
14 changes: 10 additions & 4 deletions src/tests/test_pcurves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,12 @@ class Pcurve_Point_Tests final : public Test {
const auto mul2_table = curve->mul2_setup(pt1, pt2);

const auto ref = (curve->mul(pt1, s1, rng) + curve->mul(pt2, s2, rng)).to_affine();
const auto mul2t = curve->mul2_vartime(*mul2_table, s1, s2).to_affine();

result.test_eq("ref == mul2t", ref.serialize(), mul2t.serialize());
if(auto mul2pt = curve->mul2_vartime(*mul2_table, s1, s2)) {
result.test_eq("ref == mul2t", ref.serialize(), mul2pt->to_affine().serialize());
} else {
result.confirm("ref is identity", ref.is_identity());
}
}

// Test cases where the two points have a linear relation
Expand All @@ -314,9 +317,12 @@ class Pcurve_Point_Tests final : public Test {
const auto mul2_table = curve->mul2_setup(pt1, pt2);

const auto ref = (curve->mul(pt1, s1, rng) + curve->mul(pt2, s2, rng)).to_affine();
const auto mul2t = curve->mul2_vartime(*mul2_table, s1, s2).to_affine();

result.test_eq("ref == mul2t", ref.serialize(), mul2t.serialize());
if(auto mul2pt = curve->mul2_vartime(*mul2_table, s1, s2)) {
result.test_eq("ref == mul2t", ref.serialize(), mul2pt->to_affine().serialize());
} else {
result.confirm("ref is identity", ref.is_identity());
}
}

result.end_timer();
Expand Down

0 comments on commit d24c2c3

Please sign in to comment.