From fb67ece4407c952ac53f8fb2b8b1f61a93660fe0 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Fri, 12 Jul 2024 09:10:51 -0400 Subject: [PATCH] In pcurves point mul, handle a missing/unseeded RNG In certain contexts we may not have an RNG available and yet still need to perform a point multiplication. --- src/lib/math/pcurves/pcurves_impl.h | 21 ++++++++++++++++++++- src/tests/test_pcurves.cpp | 11 +++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/lib/math/pcurves/pcurves_impl.h b/src/lib/math/pcurves/pcurves_impl.h index 971b9e38235..f18324800de 100644 --- a/src/lib/math/pcurves/pcurves_impl.h +++ b/src/lib/math/pcurves/pcurves_impl.h @@ -815,6 +815,10 @@ class ProjectiveCurvePoint { } void randomize_rep(RandomNumberGenerator& rng) { + if(!rng.is_seeded()) { + return; + } + auto r = FieldElement::random(rng); auto r2 = r.square(); @@ -966,7 +970,22 @@ class BlindedScalarBits final { constexpr size_t n_words = C::NW.size(); uint8_t maskb[mask_bytes] = {0}; - rng.randomize(maskb, mask_bytes); + if(rng.is_seeded()) { + rng.randomize(maskb, mask_bytes); + } else { + // If we don't have an RNG we don't have many good options. We + // could just omit the blinding entirely, but this changes the + // size of the blinded scalar, which we're expecting otherwise is + // knowable at compile time. So generate a mask by XORing the + // bytes of the scalar together. At worst, it's equivalent to + // omitting the blinding entirely. + + std::array sbytes; + scalar.serialize_to(sbytes); + for(size_t i = 0; i != sbytes.size(); ++i) { + maskb[i % mask_bytes] ^= sbytes[i]; + } + } W mask[n_words] = {0}; load_le(mask, maskb, mask_words); diff --git a/src/tests/test_pcurves.cpp b/src/tests/test_pcurves.cpp index 1d88022859c..0283677a242 100644 --- a/src/tests/test_pcurves.cpp +++ b/src/tests/test_pcurves.cpp @@ -29,15 +29,22 @@ class Pcurve_Basemul_Tests final : public Text_Based_Test { const auto P_bytes = vars.get_req_bin("P"); auto& rng = Test::rng(); + Botan::Null_RNG null_rng; if(auto curve = Botan::PCurve::PrimeOrderCurve::from_name(group_id)) { if(auto scalar = curve->deserialize_scalar(k_bytes)) { auto pt2 = curve->mul_by_g(scalar.value(), rng).to_affine().serialize(); result.test_eq("mul_by_g correct", pt2, P_bytes); + auto pt3 = curve->mul_by_g(scalar.value(), null_rng).to_affine().serialize(); + result.test_eq("mul_by_g (Null_RNG) correct", pt3, P_bytes); + auto g = curve->generator(); - auto pt3 = curve->mul(g, scalar.value(), rng).to_affine().serialize(); - result.test_eq("mul correct", pt3, P_bytes); + auto pt4 = curve->mul(g, scalar.value(), rng).to_affine().serialize(); + result.test_eq("mul correct", pt4, P_bytes); + + auto pt5 = curve->mul(g, scalar.value(), null_rng).to_affine().serialize(); + result.test_eq("mul correct", pt5, P_bytes); } else { result.test_failure("Curve rejected scalar input"); }