From e47d451fe6a2883962c2e76a6b8042bf18f4182e Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Mon, 15 Jul 2024 03:45:54 -0400 Subject: [PATCH] Add precomputed addition chains for P-384 and P-521 scalar inversion Saves approximately 11K cycles for P-384 and 36K cycles for P-521, improving ECDSA signing for both curves by ~4%. GH #4027 #1479 --- .../math/pcurves/pcurves_impl/pcurves_wrap.h | 14 +- .../pcurves_secp384r1/pcurves_secp384r1.cpp | 115 ++++++++++++++++ .../pcurves_secp521r1/pcurves_secp521r1.cpp | 125 ++++++++++++++++++ 3 files changed, 253 insertions(+), 1 deletion(-) diff --git a/src/lib/math/pcurves/pcurves_impl/pcurves_wrap.h b/src/lib/math/pcurves/pcurves_impl/pcurves_wrap.h index fceb9994ef2..aaf8fbb4478 100644 --- a/src/lib/math/pcurves/pcurves_impl/pcurves_wrap.h +++ b/src/lib/math/pcurves/pcurves_impl/pcurves_wrap.h @@ -17,6 +17,11 @@ concept curve_supports_fe_invert2 = requires(const typename C::FieldElement& fe) { C::fe_invert2(fe) } -> std::same_as; }; +template +concept curve_supports_scalar_invert = requires(const typename C::FieldElement& fe) { + { C::scalar_invert(fe) } -> std::same_as; +}; + template class PrimeOrderCurveImpl final : public PrimeOrderCurve { public: @@ -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) { + 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()); } diff --git a/src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp b/src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp index c8537bb1264..f6b2a3b20a8 100644 --- a/src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp +++ b/src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp @@ -181,6 +181,121 @@ class Curve final : public EllipticCurve { 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 diff --git a/src/lib/math/pcurves/pcurves_secp521r1/pcurves_secp521r1.cpp b/src/lib/math/pcurves/pcurves_secp521r1/pcurves_secp521r1.cpp index 220e5a2cbe4..1dc94043df3 100644 --- a/src/lib/math/pcurves/pcurves_secp521r1/pcurves_secp521r1.cpp +++ b/src/lib/math/pcurves/pcurves_secp521r1/pcurves_secp521r1.cpp @@ -108,6 +108,131 @@ class Curve final : public EllipticCurve { 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