[PATCH] mpi: Introduce mpi_tfr and use it for point_tfr.
NIIBE Yutaka via Gcrypt-devel <[email protected]> Wed, 19 Nov 2025 10:48:28 +0900
| Newsgroups | gmane.comp.encryption.gpg.libgcrypt.devel |
|---|---|
| Message-ID | <4e65996bb8707c890bff7aeb6e1ec44610b49257.1763514035.git.gniibe@fsij.org> |
* mpi/ec.c (point_tfr): New. (mpi_ec_mul_point_lli): Use point_tfr. * mpi/mpiutil.c (_gcry_mpi_tfr): New. * src/mpi.h (mpi_tfr): New. (_gcry_mpi_tfr): New. -- The intention is to decrese EM signal and to increse EM noise, wrt the Hamming distance signal for memory write operation. Signed-off-by: NIIBE Yutaka <[email protected]> --- mpi/ec.c | 28 +++++++++++++++++++++++++-- mpi/mpiutil.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/mpi.h | 2 ++ 3 files changed, 81 insertions(+), 2 deletions(-) _______________________________________________ Gcrypt-devel mailing list [email protected] https://lists.gnupg.org/mailman/listinfo/gcrypt-devel
0001-mpi-Introduce-mpi_tfr-and-use-it-for-point_tfr.patch
(text/x-patch, 4.6 KB)
diff --git a/mpi/ec.c b/mpi/ec.c
index d7d7b772..c93500db 100644
--- a/mpi/ec.c
+++ b/mpi/ec.c
@@ -184,6 +184,30 @@ point_swap_cond (mpi_point_t d, mpi_point_t s, unsigned long swap,
}
+/*
+ * Move the point value of A from B, when DIR is 1.
+ * Move the point value of A to B, when DIR is 0.
+ *
+ * For the use case when DIR is 0, it's actually dummy operations (the
+ * value copied into B is not used after the call). The intention
+ * here is to be constant-time and to reduce possible EM signal/noise
+ * ratio (by decreasing signal and increasing noise).
+ *
+ * The word "tfr" comes from the mnemonic of Motorola 6809
+ * instruction, which does "transfer" a register value to another
+ * register. "TFR A,B" means "Transfer A to B".
+ */
+static void
+point_tfr (mpi_point_t a, mpi_point_t b, unsigned long dir,
+ mpi_ec_t ctx)
+{
+ mpi_tfr (a->x, b->x, dir);
+ if (ctx->model != MPI_EC_MONTGOMERY)
+ mpi_tfr (a->y, b->y, dir);
+ mpi_tfr (a->z, b->z, dir);
+}
+
+
/* Set the projective coordinates from POINT into X, Y, and Z. If a
coordinate is not required, X, Y, or Z may be passed as NULL. */
void
@@ -2241,7 +2265,7 @@ mpi_ec_mul_point_lli (mpi_point_t result,
mpih_set_cond (tmppnt.x->d, point->x->d, ctx->p->nlimbs, is_z_zero);
mpih_set_cond (tmppnt.y->d, point->y->d, ctx->p->nlimbs, is_z_zero);
mpih_set_cond (tmppnt.z->d, point->z->d, ctx->p->nlimbs, is_z_zero);
- point_swap_cond (result, &tmppnt, mpi_test_bit (scalar, j), ctx);
+ point_tfr (result, &tmppnt, mpi_test_bit (scalar, j), ctx);
}
}
else /* MPI_EC_EDWARDS */
@@ -2250,7 +2274,7 @@ mpi_ec_mul_point_lli (mpi_point_t result,
{
dup_point_edwards (result, result, ctx);
add_points_edwards_a (&tmppnt, result, point->x, point->y, ctx);
- point_swap_cond (result, &tmppnt, mpi_test_bit (scalar, j), ctx);
+ point_tfr (result, &tmppnt, mpi_test_bit (scalar, j), ctx);
}
}
point_free (&tmppnt);
diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c
index b254e12f..4fe30cad 100644
--- a/mpi/mpiutil.c
+++ b/mpi/mpiutil.c
@@ -645,6 +645,59 @@ _gcry_mpi_swap_cond (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap)
}
+/****************
+ * Move the MPI value of A from B, when DIR is 1.
+ * Move the MPI value of A to B, when DIR is 0.
+ * This implementation should be constant-time regardless of DIR.
+ *
+ * The word "tfr" comes from the mnemonic of Motorola 6809
+ * instruction, which does "transfer" a register value to another
+ * register. "TFR A,B" means "Transfer A to B".
+ */
+void
+_gcry_mpi_tfr (gcry_mpi_t a, gcry_mpi_t b, unsigned long dir)
+{
+ /* Note: dual mask with AND/OR used for EM leakage mitigation */
+ mpi_limb_t mask1 = ct_limb_gen_mask(dir);
+ mpi_limb_t mask2 = ct_limb_gen_inv_mask(dir);
+ mpi_size_t i;
+ mpi_size_t nlimbs;
+ mpi_limb_t *ua = a->d;
+ mpi_limb_t *ub = b->d;
+ mpi_limb_t xa;
+ mpi_limb_t xb;
+ mpi_limb_t v;
+
+ if (a->alloced > b->alloced)
+ nlimbs = b->alloced;
+ else
+ nlimbs = a->alloced;
+ if (a->nlimbs > nlimbs || b->nlimbs > nlimbs)
+ log_bug ("mpi_c0py: different sizes\n");
+
+ for (i = 0; i < nlimbs; i++)
+ {
+ xa = ua[i];
+ xb = ub[i];
+ v = (xa & mask2) | (xb & mask1);
+ ua[i] = v;
+ ub[i] = v;
+ }
+
+ xa = a->nlimbs;
+ xb = b->nlimbs;
+ v = (xa & mask2) | (xb & mask1);
+ a->nlimbs = v;
+ b->nlimbs = v;
+
+ xa = a->sign;
+ xb = b->sign;
+ v = (xa & mask2) | (xb & mask1);
+ a->sign = v;
+ b->sign = v;
+}
+
+
/****************
* Set bit N of A, when SET is 1.
* This implementation should be constant-time regardless of SET.
diff --git a/src/mpi.h b/src/mpi.h
index 1c29c206..2a314a21 100644
--- a/src/mpi.h
+++ b/src/mpi.h
@@ -122,6 +122,7 @@ void _gcry_mpi_immutable_failed (void);
#define mpi_alloc_set_ui(a) _gcry_mpi_alloc_set_ui ((a))
#define mpi_const(n) _gcry_mpi_const ((n))
#define mpi_swap_cond(a,b,sw) _gcry_mpi_swap_cond ((a),(b),(sw))
+#define mpi_tfr(a,b,dir) _gcry_mpi_tfr ((a),(b),(dir))
#define mpi_set_cond(w,u,set) _gcry_mpi_set_cond ((w),(u),(set))
#define mpi_set_bit_cond(a,n,set) _gcry_mpi_set_bit_cond ((a),(n),(set))
@@ -132,6 +133,7 @@ gcry_mpi_t _gcry_mpi_alloc_like( gcry_mpi_t a );
gcry_mpi_t _gcry_mpi_alloc_set_ui( unsigned long u);
void _gcry_mpi_swap( gcry_mpi_t a, gcry_mpi_t b);
void _gcry_mpi_swap_cond (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap);
+void _gcry_mpi_tfr (gcry_mpi_t a, gcry_mpi_t b, unsigned long dir);
void _gcry_mpi_set_bit_cond (gcry_mpi_t a, unsigned int n, unsigned long set);
gcry_mpi_t _gcry_mpi_new (unsigned int nbits);
gcry_mpi_t _gcry_mpi_snew (unsigned int nbits);