[PATCH] Move bounds check inside ECC scalar multiply.

Nick nick at kousu.ca
Wed May 29 22:40:07 CEST 2019


The project's README says that contributions are welcome, but it's not that obvious to me how. With that said, I hope this is acceptable:

I've submitted a merge request to your mirror. It makes `compute_kG` and `compute_kP` safer and more consistent to use.

https://salsa.debian.org/gnuk-team/gnuk/gnuk/merge_requests/3

I welcome feedback to help improve this patch to a point where it would be acceptable for inclusion in your great fully free software project. As I said on the MR, I assign my copyright to the FSIJ, assuming it gets accepted.

It's also included below

---
 src/ecc.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/ecc.c b/src/ecc.c
index 2d637e9..4437e3e 100644
--- a/src/ecc.c
+++ b/src/ecc.c
@@ -119,6 +119,12 @@ FUNC(compute_kG) (ac *X, const bn256 *K)
   jpc Q[1], tmp[1], *dst;
   int i;
   int vk;
+
+  if (bn256_is_zero(K)) /* < 1, it's too small. */
+    return -1;
+  if (bn256_sub(K_dash, K, N) == 0) /* >= N, it's too big.  */
+    return -1;
+
   uint32_t k_is_even = bn256_is_even (K);
 
   bn256_sub_uint (K_dash, K, k_is_even);
@@ -241,7 +247,6 @@ FUNC(compute_kP) (ac *X, const bn256 *K, const ac *P)
   uint8_t index[86]; /* Lower 2-bit for index absolute value, msb is
 			for sign (encoded as: 0 means 1, 1 means -1).  */
   bn256 K_dash[1];
-  uint32_t k_is_even = bn256_is_even (K);
   jpc Q[1], tmp[1], *dst;
   int i;
   int vk;
@@ -251,9 +256,13 @@ FUNC(compute_kP) (ac *X, const bn256 *K, const ac *P)
   if (point_is_on_the_curve (P) < 0)
     return -1;
 
-  if (bn256_sub (K_dash, K, N) == 0)	/* >= N, it's too big.  */
+  if (bn256_is_zero(K)) /* < 1, it's too small. */
+    return -1;
+  if (bn256_sub(K_dash, K, N) == 0) /* >= N, it's too big.  */
     return -1;
 
+  uint32_t k_is_even = bn256_is_even (K);
+
   bn256_sub_uint (K_dash, K, k_is_even);
   /* It keeps the condition: 1 <= K' <= N - 2, and K' is odd.  */
 
@@ -337,12 +346,9 @@ FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
       do
 	{
 	  bn256_random (k);
-	  if (bn256_add_uint (k, k, 1))
-	    continue;
-	  if (bn256_sub (tmp_k, k, N) == 0)	/* >= N, it's too big.  */
+	  if(FUNC(compute_kG) (KG, k) < 0)
 	    continue;
 	  /* 1 <= k <= N - 1 */
-	  FUNC(compute_kG) (KG, k);
 	  borrow = bn256_sub (r, KG->x, N);
 	  if (borrow)
 	    memcpy (r, KG->x, sizeof (bn256));
@@ -372,8 +378,8 @@ FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
 /**
  * @brief Check if a secret d0 is valid or not
  *
- * @param D0	scalar D0: secret
- * @param D1	scalar D1: secret candidate N-D0
+ * @param D0	scalar D0: secret candidate
+ * @param D1	scalar D1: secret candidate projected to N-D0 (output)
  *
  * Return 0 on error.
  * Return -1 when D1 should be used as the secret
@@ -384,12 +390,12 @@ FUNC(check_secret) (const bn256 *d0, bn256 *d1)
 {
   ac Q0[1], Q1[1];
 
-  if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) != 0)
-    /* == 0 or >= N, it's not valid.  */
+  if(FUNC(compute_kG) (Q0, d0) < 0)
+    return 0;
+  bn256_sub (d1, N, d0); // carry is not checked here;
+                         // the bounds check in compute_kG should hace caught the carry case
+  if(FUNC(compute_kG) (Q1, d1) < 0)
     return 0;
-
-  FUNC(compute_kG) (Q0, d0);
-  FUNC(compute_kG) (Q1, d1);
 
   /*
    * Jivsov compliant key check
-- 
2.20.1 (Apple Git-117)



More information about the Gnuk-users mailing list