Skip to content

Commit

Permalink
Add precomputed addition chains for P-384 and P-521 scalar inversion
Browse files Browse the repository at this point in the history
Saves approximately 11K cycles for P-384 and 36K cycles for P-521,
improving ECDSA signing for both curves by ~4%.

GH #4027 #1479
  • Loading branch information
randombit committed Jul 15, 2024
1 parent 25356e1 commit e47d451
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/lib/math/pcurves/pcurves_impl/pcurves_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ concept curve_supports_fe_invert2 = requires(const typename C::FieldElement& fe)
{ C::fe_invert2(fe) } -> std::same_as<typename C::FieldElement>;
};

template <typename C>
concept curve_supports_scalar_invert = requires(const typename C::FieldElement& fe) {
{ C::scalar_invert(fe) } -> std::same_as<typename C::FieldElement>;
};

template <typename C>
class PrimeOrderCurveImpl final : public PrimeOrderCurve {
public:
Expand Down Expand Up @@ -221,7 +226,14 @@ class PrimeOrderCurveImpl final : public PrimeOrderCurve {

Scalar scalar_square(const Scalar& s) const override { return stash(from_stash(s).square()); }

Scalar scalar_invert(const Scalar& s) const override { return stash(from_stash(s).invert()); }
Scalar scalar_invert(const Scalar& ss) const override {
auto s = from_stash(ss);
if constexpr(curve_supports_scalar_invert<C>) {
return stash(C::scalar_invert(s));
} else {
return stash(s.invert());
}
}

Scalar scalar_negate(const Scalar& s) const override { return stash(from_stash(s).negate()); }

Expand Down
115 changes: 115 additions & 0 deletions src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,121 @@ class Curve final : public EllipticCurve<Params, Secp384r1Rep> {

return r;
}

static Scalar scalar_invert(const Scalar& x) {
// Generated using https://github.com/mmcloughlin/addchain

auto t3 = x.square();
auto t1 = x * t3;
auto t0 = t3 * t1;
auto t2 = t3 * t0;
auto t4 = t3 * t2;
auto z = t3 * t4;
auto t5 = t3 * z;
t3 *= t5;
auto t6 = t3.square();
t6 *= x;
auto t8 = t6;
t8.square_n(2);
auto t9 = t8.square();
auto t7 = t9.square();
auto t10 = t7;
t10.square_n(5);
t7 *= t10;
t10 = t7;
t10.square_n(10);
t7 *= t10;
t10 = t7;
t10.square_n(4);
t9 *= t10;
t9.square_n(21);
t7 *= t9;
t9 = t7;
t9.square_n(3);
t8 *= t9;
t8.square_n(47);
t7 *= t8;
t8 = t7;
t8.square_n(95);
t7 *= t8;
t7 *= t3;
t7.square_n(6);
t7 *= t2;
t7.square_n(3);
t7 *= t1;
t7.square_n(7);
t7 *= t5;
t7.square_n(6);
t7 *= t5;
t7 = t7.square();
t7 *= x;
t7.square_n(11);
t7 *= t6;
t7.square_n(2);
t7 *= x;
t7.square_n(8);
t7 *= t5;
t7.square_n(2);
t7 *= t1;
t7.square_n(6);
t7 *= z;
t7.square_n(4);
t7 *= t2;
t7.square_n(6);
t6 *= t7;
t6.square_n(5);
t6 *= z;
t6.square_n(10);
t6 *= t5;
t6.square_n(9);
t5 *= t6;
t5.square_n(4);
t5 *= z;
t5.square_n(6);
t4 *= t5;
t4.square_n(3);
t4 *= x;
t4.square_n(7);
t4 *= z;
t4.square_n(7);
t4 *= t0;
t4.square_n(5);
t4 *= t2;
t4.square_n(5);
t3 *= t4;
t3.square_n(5);
t3 *= z;
t3.square_n(4);
t3 *= z;
t3.square_n(5);
t2 *= t3;
t2.square_n(3);
t2 *= t1;
t2.square_n(7);
t2 *= t1;
t2.square_n(6);
t2 *= z;
t2.square_n(4);
t2 *= t0;
t2.square_n(3);
t2 *= t1;
t2.square_n(4);
t2 *= t1;
t2.square_n(4);
t1 *= t2;
t1.square_n(6);
t1 *= t0;
t1.square_n(5);
t0 *= t1;
t0.square_n(6);
z *= t0;
z = z.square();
z *= x;
z.square_n(4);
z *= x;

return z;
}
};

} // namespace secp384r1
Expand Down
125 changes: 125 additions & 0 deletions src/lib/math/pcurves/pcurves_secp521r1/pcurves_secp521r1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,131 @@ class Curve final : public EllipticCurve<Params, P521Rep> {

return r;
}

static Scalar scalar_invert(const Scalar& x) {
// Generated using https://github.com/mmcloughlin/addchain

auto t2 = x.square();
auto t13 = t2 * x;
auto t4 = t13 * x;
auto z = t13 * t4;
auto t5 = x * z;
auto t16 = t13 * t5;
auto t10 = t16 * t2;
auto t18 = t10 * t2;
auto t1 = t18 * t2;
auto t12 = t1 * t2;
auto t15 = t12 * t4;
auto t0 = t15 * t2;
auto t3 = t0 * t2;
auto t6 = t2 * t3;
auto t11 = t5 * t6;
auto t14 = t11 * t4;
auto t9 = t14 * t4;
auto t17 = t2 * t9;
auto t7 = t17 * t4;
t4 *= t7;
auto t8 = t2 * t4;
t5 = t2 * t8;
t2 *= t5;
auto t19 = t2;
t19.square_n(3);
t15 *= t19;
t19 = t15.square();
auto t20 = t19;
t20.square_n(8);
t20 *= t15;
t20.square_n(10);
t19 *= t20;
t20 = t19;
t20.square_n(8);
t20 *= t15;
t20.square_n(28);
t19 *= t20;
t20 = t19;
t20.square_n(63);
t19 *= t20;
t20 = t19;
t20.square_n(8);
t20 *= t15;
t20.square_n(127);
t19 *= t20;
t19 *= x;
t19.square_n(7);
t19 *= t11;
t19.square_n(5);
t19 *= t13;
t19.square_n(8);
t19 *= t10;
t19.square_n(8);
t19 *= t18;
t19.square_n(11);
t19 *= t5;
t19.square_n(4);
t18 *= t19;
t18.square_n(8);
t17 *= t18;
t17.square_n(6);
t17 *= t11;
t17.square_n(5);
t17 *= t12;
t17.square_n(5);
t16 *= t17;
t16.square_n(10);
t15 *= t16;
t15.square_n(4);
t15 *= t13;
t15.square_n(15);
t14 *= t15;
t14.square_n(9);
t14 *= t2;
t14.square_n(2);
t13 *= t14;
t13.square_n(9);
t12 *= t13;
t12.square_n(7);
t11 *= t12;
t11.square_n(4);
t10 *= t11;
t10.square_n(12);
t10 *= t5;
t10.square_n(6);
t9 *= t10;
t9.square_n(7);
t8 *= t9;
t8.square_n(8);
t8 *= t4;
t8.square_n(8);
t8 *= t1;
t8.square_n(8);
t7 *= t8;
t7.square_n(5);
t7 *= t1;
t7.square_n(9);
t7 *= t2;
t7.square_n(6);
t6 *= t7;
t6.square_n(7);
t5 *= t6;
t5.square_n(7);
t4 *= t5;
t4.square_n(5);
t3 *= t4;
t3.square_n(4);
t3 *= z;
t3.square_n(9);
t2 *= t3;
t2.square_n(7);
t1 *= t2;
t1.square_n(5);
t1 *= z;
t1.square_n(9);
t0 *= t1;
t0.square_n(10);
z *= t0;

return z;
}
};

} // namespace secp521r1
Expand Down

0 comments on commit e47d451

Please sign in to comment.