From a17e38ed244967e3ed443da556915861c9d4f818 Mon Sep 17 00:00:00 2001 From: Lukas Burkhalter Date: Tue, 24 Feb 2026 17:29:39 +0100 Subject: [PATCH] feat: Improve encrypt/verify performance Limit exponentiation to the bit length of e to reduce computation time. This is safe since e is public. --- src/algorithms/rsa.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/algorithms/rsa.rs b/src/algorithms/rsa.rs index 18ca94de..3c444a21 100644 --- a/src/algorithms/rsa.rs +++ b/src/algorithms/rsa.rs @@ -18,7 +18,8 @@ use crate::traits::keys::{PrivateKeyParts, PublicKeyParts}; /// or signature scheme. See the [module-level documentation][crate::hazmat] for more information. #[inline] pub fn rsa_encrypt(key: &K, m: &BoxedUint) -> Result { - let res = pow_mod_params(m, key.e(), key.n_params()); + let e = key.e(); + let res = pow_mod_params_vartime_exp_bits(m, e, e.bits(), key.n_params()); Ok(res) } @@ -195,7 +196,8 @@ fn blind( let blinded = { // r^e (mod n) - let mut rpowe = pow_mod_params(&r, key.e(), n_params); + let e = key.e(); + let mut rpowe = pow_mod_params_vartime_exp_bits(&r, e, e.bits(), n_params); // c * r^e (mod n) let c = c.mul_mod(&rpowe, n_params.modulus().as_nz_ref()); rpowe.zeroize(); @@ -234,6 +236,19 @@ fn pow_mod_params(base: &BoxedUint, exp: &BoxedUint, n_params: &BoxedMontyParams base.pow(exp).retrieve() } +/// Computes `base.pow_mod(exp, n)` with a bounded exponent and precomputed `n_params`. +/// +/// The exponent bit length `exp_bits` may be leaked in the time pattern. +fn pow_mod_params_vartime_exp_bits( + base: &BoxedUint, + exp: &BoxedUint, + exp_bits: u32, + n_params: &BoxedMontyParams, +) -> BoxedUint { + let base = reduce_vartime(base, n_params); + base.pow_bounded_exp(exp, exp_bits).retrieve() +} + fn reduce_vartime(n: &BoxedUint, p: &BoxedMontyParams) -> BoxedMontyForm { let modulus = p.modulus().as_nz_ref().clone(); let n_reduced = n.rem_vartime(&modulus).resize_unchecked(p.bits_precision());