]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Reduce output range of ecc_mod_sub.
authorNiels Möller <nisse@lysator.liu.se>
Tue, 16 Aug 2022 17:47:20 +0000 (19:47 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Tue, 16 Aug 2022 17:47:20 +0000 (19:47 +0200)
* ecc-mod-arith.c (ecc_mod_sub): Ensure that if inputs are in the
range 0 <= a, b < 2m, then output is in the same range.
* eccdata.c (output_curve): New outputs ecc_Bm2p and ecc_Bm2q.
* ecc-internal.h (struct ecc_modulo): New member Bm2m (B^size -
2m), needed by ecc_mod_sub. Update all curves.
* testsuite/ecc-mod-arith-test.c: New tests for ecc_mod_add and
ecc_mod_sub.

15 files changed:
ChangeLog
ecc-curve25519.c
ecc-curve448.c
ecc-gost-gc256b.c
ecc-gost-gc512a.c
ecc-internal.h
ecc-mod-arith.c
ecc-secp192r1.c
ecc-secp224r1.c
ecc-secp256r1.c
ecc-secp384r1.c
ecc-secp521r1.c
eccdata.c
testsuite/Makefile.in
testsuite/ecc-mod-arith-test.c [new file with mode: 0644]

index 15ad3384d2bad7537167c8e9663dd726f20b526f..083d443a17300d9ffa21287a0a17053a2e240453 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2022-08-16  Niels Möller  <nisse@lysator.liu.se>
 
+       * ecc-mod-arith.c (ecc_mod_sub): Ensure that if inputs are in the
+       range 0 <= a, b < 2m, then output is in the same range.
+       * eccdata.c (output_curve): New outputs ecc_Bm2p and ecc_Bm2q.
+       * ecc-internal.h (struct ecc_modulo): New member Bm2m (B^size -
+       2m), needed by ecc_mod_sub. Update all curves.
+       * testsuite/ecc-mod-arith-test.c: New tests for ecc_mod_add and
+       ecc_mod_sub.
+
        * eccdata.c (output_modulo): Output the limb size, delete return
        value.
        (output_curve): Update calls to output_modulo, other minor cleanup.
index 56abcf233ce36db3df4cf3bb9b3dcf3562d3ff4f..539bff2211b4fec9e23ace15b078c1353f47a53e 100644 (file)
@@ -266,6 +266,7 @@ const struct ecc_curve _nettle_curve25519 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     NULL,
     ecc_pp1h,
 
@@ -287,6 +288,7 @@ const struct ecc_curve _nettle_curve25519 =
     ecc_q,
     ecc_Bmodq,  
     ecc_mBmodq_shifted, /* Use q - 2^{252} instead. */
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index 1bd4e11f76cd8f005b8161086029443f0dcef189..daef56cc83654ddf084012194c30cb9916681eba 100644 (file)
@@ -220,6 +220,7 @@ const struct ecc_curve _nettle_curve448 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     NULL,
     ecc_pp1h,
 
@@ -241,6 +242,7 @@ const struct ecc_curve _nettle_curve448 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index 0cf753e4631bb038da291d1ac31e3524cfe83b44..df9cbb5816fc2be88ffae64aba67f3854085ba49 100644 (file)
@@ -71,6 +71,7 @@ const struct ecc_curve _nettle_gost_gc256b =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
 
     ecc_pp1h,
@@ -92,6 +93,7 @@ const struct ecc_curve _nettle_gost_gc256b =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index 338ed00194ba87b7af1ee55fc3a68f94b8b486a9..3807b57e66e23b160b5ee55367fc7b3b53509658 100644 (file)
@@ -71,6 +71,7 @@ const struct ecc_curve _nettle_gost_gc512a =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
 
     ecc_pp1h,
@@ -92,6 +93,7 @@ const struct ecc_curve _nettle_gost_gc512a =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index eb53a9b3fa728e57bbaa386de6732ee59992cba4..b04d80ce2c012999a4b8a380a18826e6ea1542df 100644 (file)
@@ -178,6 +178,10 @@ struct ecc_modulo
      interest, usually B has trailing zeros and this is B shifted
      right. */
   const mp_limb_t *B_shifted;
+  /* For ecc_mod_sub: B^size - 2m, if that doesn't underflow.
+     Otherwise, same as B */
+  const mp_limb_t *Bm2m;
+
   /* m +/- 1, for redc, excluding redc_size low limbs. */
   const mp_limb_t *redc_mpm1;
   /* (m+1)/2 */
@@ -260,6 +264,8 @@ ecc_mod_equal_p (const struct ecc_modulo *m, const mp_limb_t *a,
 void
 ecc_mod_add (const struct ecc_modulo *m, mp_limb_t *rp,
             const mp_limb_t *ap, const mp_limb_t *bp);
+
+/* If inputs are in the range 0 <= a, b < 2m, then so is the output. */
 void
 ecc_mod_sub (const struct ecc_modulo *m, mp_limb_t *rp,
             const mp_limb_t *ap, const mp_limb_t *bp);
index 310cbb1d68b1699f26f1fb3b2be2dde2f17720e9..d01378643c3b412697ccdc3661ba4148271b67ec 100644 (file)
@@ -85,7 +85,20 @@ ecc_mod_sub (const struct ecc_modulo *m, mp_limb_t *rp,
 {
   mp_limb_t cy;
   cy = mpn_sub_n (rp, ap, bp, m->size);
-  cy = mpn_cnd_sub_n (cy, rp, rp, m->B, m->size);
+  /* The adjustments for this function work differently depending on
+     the value of the most significant bit of m.
+
+     If m has a most significant bit of zero, then the first
+     adjustment step conditionally adds 2m. If in addition, inputs are
+     in the 0 <= a,b < 2m range, then the first adjustment guarantees
+     that result is in that same range. The second adjustment step is
+     needed only if b > 2m, it then ensures output is correct modulo
+     m, but nothing more.
+
+     If m has a most significant bit of one, Bm2m and B are the same,
+     and this function works analogously to ecc_mod_add.
+   */
+  cy = mpn_cnd_sub_n (cy, rp, rp, m->Bm2m, m->size);
   cy = mpn_cnd_sub_n (cy, rp, rp, m->B, m->size);
   assert (cy == 0);  
 }
index 391ba52817f409ddd38b68da343d757e3b099095..4a07bca31c3f83d404436ea3e6897cd90bce407f 100644 (file)
@@ -247,7 +247,8 @@ const struct ecc_curve _nettle_secp_192r1 =
 
     ecc_p,
     ecc_Bmodp,
-    ecc_Bmodp_shifted,    
+    ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
     ecc_pp1h,
 
@@ -269,6 +270,7 @@ const struct ecc_curve _nettle_secp_192r1 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index bb3212985114a772a9f45e9ed9b00423b950c4c4..b2a335ece8b03dcbbc970f521c5b8472ed35fd11 100644 (file)
@@ -223,6 +223,7 @@ const struct ecc_curve _nettle_secp_224r1 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
     ecc_pp1h,
 
@@ -244,6 +245,7 @@ const struct ecc_curve _nettle_secp_224r1 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index e1a14b9090216294ff62ced5d34fe845e215752f..4848dfe3191ac27df0891adc4af48ad5ad76eaad 100644 (file)
@@ -343,6 +343,7 @@ const struct ecc_curve _nettle_secp_256r1 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
     ecc_pp1h,
 
@@ -364,6 +365,7 @@ const struct ecc_curve _nettle_secp_256r1 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index 39716dffdc9e676bec686f37093eb20139cf4ce5..abac5e6d449f61f4927a11759878042014b4b22c 100644 (file)
@@ -314,6 +314,7 @@ const struct ecc_curve _nettle_secp_384r1 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
     ecc_pp1h,
 
@@ -335,6 +336,7 @@ const struct ecc_curve _nettle_secp_384r1 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index 24d0b53a75d2c71b191a1c0a2b8dad2d74807534..8ab7b4bf0da671dc24d4c72f30e107ec73a760a9 100644 (file)
@@ -169,6 +169,7 @@ const struct ecc_curve _nettle_secp_521r1 =
     ecc_p,
     ecc_Bmodp,
     ecc_Bmodp_shifted,
+    ecc_Bm2p,
     ecc_redc_ppm1,
     ecc_pp1h,
 
@@ -190,6 +191,7 @@ const struct ecc_curve _nettle_secp_521r1 =
     ecc_q,
     ecc_Bmodq,
     ecc_Bmodq_shifted,
+    ecc_Bm2q,
     NULL,
     ecc_qp1h,
 
index f9b2f4029731100f88688edf242e32ac0f817ff3..4459f5d233937f5c8bc71cb5db69bfd92f6af271 100644 (file)
--- a/eccdata.c
+++ b/eccdata.c
@@ -1226,6 +1226,11 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb)
     {
       int shift;
 
+      mpz_set_ui (t, 0);
+      mpz_setbit (t, limb_size * bits_per_limb);
+      mpz_submul_ui (t, ecc->p, 2);
+      output_bignum ("ecc_Bm2p", t, limb_size, bits_per_limb);
+
       mpz_set_ui (t, 0);
       mpz_setbit (t, ecc->bit_size);
       mpz_sub (t, t, ecc->p);      
@@ -1258,18 +1263,28 @@ output_curve (const struct ecc_curve *ecc, unsigned bits_per_limb)
        }
     }
   else
-    printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
+    {
+      printf ("#define ecc_Bmodp_shifted ecc_Bmodp\n");
+      printf ("#define ecc_Bm2p ecc_Bmodp\n");
+    }
 
   if (qbits < limb_size * bits_per_limb)
     {
+      mpz_set_ui (t, 0);
+      mpz_setbit (t, limb_size * bits_per_limb);
+      mpz_submul_ui (t, ecc->q, 2);
+      output_bignum ("ecc_Bm2q", t, limb_size, bits_per_limb);
+
       mpz_set_ui (t, 0);
       mpz_setbit (t, qbits);
       mpz_sub (t, t, ecc->q);      
-      output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb);      
+      output_bignum ("ecc_Bmodq_shifted", t, limb_size, bits_per_limb);
     }
   else
-    printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
-
+    {
+      printf ("#define ecc_Bmodq_shifted ecc_Bmodq\n");
+      printf ("#define ecc_Bm2q ecc_Bmodq\n");
+    }
   mpz_add_ui (t, ecc->p, 1);
   mpz_fdiv_q_2exp (t, t, 1);
   output_bignum ("ecc_pp1h", t, limb_size, bits_per_limb);      
index 6734d3e668c67728b45fc5ffd3cf2d4776369e0b..4e20c7a113767067e2b1985164ee62fd527c9e23 100644 (file)
@@ -47,8 +47,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
                     rsa-compute-root-test.c \
                     dsa-test.c dsa-keygen-test.c \
                     curve25519-dh-test.c curve448-dh-test.c \
-                    ecc-mod-test.c ecc-modinv-test.c ecc-redc-test.c \
-                    ecc-sqrt-test.c \
+                    ecc-mod-arith-test.c ecc-mod-test.c ecc-modinv-test.c \
+                    ecc-redc-test.c ecc-sqrt-test.c \
                     ecc-dup-test.c ecc-add-test.c \
                     ecc-mul-g-test.c ecc-mul-a-test.c \
                     ecdsa-sign-test.c ecdsa-verify-test.c \
diff --git a/testsuite/ecc-mod-arith-test.c b/testsuite/ecc-mod-arith-test.c
new file mode 100644 (file)
index 0000000..5692f58
--- /dev/null
@@ -0,0 +1,158 @@
+#include "testutils.h"
+
+#define MAX_SIZE (1 + 521 / GMP_NUMB_BITS)
+#define COUNT 50000
+
+static void
+test_add(const char *name,
+        const struct ecc_modulo *m,
+        const mpz_t az, const mpz_t bz)
+{
+  mp_limb_t a[MAX_SIZE];
+  mp_limb_t b[MAX_SIZE];
+  mp_limb_t t[MAX_SIZE];
+  mpz_t mz;
+  mpz_t tz;
+  mpz_t ref;
+
+  mpz_init (ref);
+  mpz_add (ref, az, bz);
+  mpz_mod (ref, ref, mpz_roinit_n (mz, m->m, m->size));
+
+  mpz_limbs_copy (a, az, m->size);
+  mpz_limbs_copy (b, bz, m->size);
+  ecc_mod_add (m, t, a, b);
+
+  if (!mpz_congruent_p (ref, mpz_roinit_n (tz, t, m->size), mz))
+    {
+      fprintf (stderr, "ecc_mod_add %s failed: bit_size = %u\n",
+              name, m->bit_size);
+
+      fprintf (stderr, "a   = ");
+      mpn_out_str (stderr, 16, a, m->size);
+      fprintf (stderr, "\nb   = ");
+      mpn_out_str (stderr, 16, b, m->size);
+      fprintf (stderr, "\nt   = ");
+      mpn_out_str (stderr, 16, t, m->size);
+      fprintf (stderr, " (bad)\nref = ");
+      mpz_out_str (stderr, 16, ref);
+      fprintf (stderr, "\n");
+      abort ();
+    }
+}
+
+static void
+test_sub(const char *name,
+        const struct ecc_modulo *m,
+        /* If range is non-null, check that 0 <= r < range. */
+        const mp_limb_t *range,
+        const mpz_t az, const mpz_t bz)
+{
+  mp_limb_t a[MAX_SIZE];
+  mp_limb_t b[MAX_SIZE];
+  mp_limb_t t[MAX_SIZE];
+  mpz_t mz;
+  mpz_t tz;
+  mpz_t ref;
+
+  mpz_init (ref);
+  mpz_sub (ref, az, bz);
+  mpz_mod (ref, ref, mpz_roinit_n (mz, m->m, m->size));
+
+  mpz_limbs_copy (a, az, m->size);
+  mpz_limbs_copy (b, bz, m->size);
+  ecc_mod_sub (m, t, a, b);
+
+  if (!mpz_congruent_p (ref, mpz_roinit_n (tz, t, m->size), mz))
+    {
+      fprintf (stderr, "ecc_mod_sub %s failed: bit_size = %u\n",
+              name, m->bit_size);
+
+      fprintf (stderr, "a   = ");
+      mpn_out_str (stderr, 16, a, m->size);
+      fprintf (stderr, "\nb   = ");
+      mpn_out_str (stderr, 16, b, m->size);
+      fprintf (stderr, "\nt   = ");
+      mpn_out_str (stderr, 16, t, m->size);
+      fprintf (stderr, " (bad)\nref = ");
+      mpz_out_str (stderr, 16, ref);
+      fprintf (stderr, "\n");
+      abort ();
+    }
+
+  if (range && mpn_cmp (t, range, m->size) >= 0)
+    {
+      fprintf (stderr, "ecc_mod_sub %s out of range: bit_size = %u\n",
+              name, m->bit_size);
+
+      fprintf (stderr, "a   = ");
+      mpn_out_str (stderr, 16, a, m->size);
+      fprintf (stderr, "\nb   = ");
+      mpn_out_str (stderr, 16, b, m->size);
+      fprintf (stderr, "\nt   = ");
+      mpn_out_str (stderr, 16, t, m->size);
+      fprintf (stderr, " \nrange = ");
+      mpn_out_str (stderr, 16, range, m->size);
+      fprintf (stderr, "\n");
+      abort ();
+    }
+}
+
+static void
+test_modulo (gmp_randstate_t rands, const char *name,
+            const struct ecc_modulo *m, unsigned count)
+{
+  mpz_t a, b;
+  unsigned j;
+
+  mpz_init (a);
+  mpz_init (b);
+
+  for (j = 0; j < count; j++)
+    {
+      if (j & 1)
+       {
+         mpz_rrandomb (a, rands, m->size * GMP_NUMB_BITS);
+         mpz_rrandomb (b, rands, m->size * GMP_NUMB_BITS);
+       }
+      else
+       {
+         mpz_urandomb (a, rands, m->size * GMP_NUMB_BITS);
+         mpz_urandomb (b, rands, m->size * GMP_NUMB_BITS);
+       }
+      test_add (name, m, a, b);
+      test_sub (name, m, NULL, a, b);
+    }
+  if (m->bit_size < m->size * GMP_NUMB_BITS)
+    {
+      mp_limb_t two_p[MAX_SIZE];
+      mpn_lshift (two_p, m->m, m->size, 1);
+      mpz_t range;
+      mpz_roinit_n (range, two_p, m->size);
+      mpz_urandomm (a, rands, range);
+      mpz_urandomm (b, rands, range);
+      test_sub (name, m, two_p, a, b);
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+void
+test_main (void)
+{
+  gmp_randstate_t rands;
+  unsigned count = COUNT;
+  unsigned i;
+
+  gmp_randinit_default (rands);
+
+  if (test_randomize(rands))
+    count *= 20;
+
+  for (i = 0; ecc_curves[i]; i++)
+    {
+      test_modulo (rands, "p", &ecc_curves[i]->p, count);
+      test_modulo (rands, "q", &ecc_curves[i]->q, count);
+    }
+  gmp_randclear (rands);
+}