Add functions to copy vli from buffers, to print vli in
big endian format, for vli mod and mod multiplication ops,
ecc point addition and ecc pub key validation.

Signed-off-by: Nitin Kumbhar <nkumb...@nvidia.com>
---
 crypto/ecc.c |  189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/crypto/ecc.c b/crypto/ecc.c
index a8c10e725138..1b8e8d248859 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -208,6 +208,42 @@ static void vli_set(u64 *dest, const u64 *src, unsigned 
int ndigits)
                dest[i] = src[i];
 }
 
+/* Copy from vli to buf.
+ * For buffers smaller than vli: copy only LSB nbytes from vli.
+ * For buffers larger than vli : fill up remaining buf with zeroes.
+ */
+void vli_copy_to_buf(u8 *dst_buf, unsigned int buf_len,
+                    const u64 *src_vli, unsigned int ndigits)
+{
+       unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+       u8 *vli = (u8 *)src_vli;
+       int i;
+
+       for (i = 0; i < buf_len && i < nbytes; i++)
+               dst_buf[i] = vli[i];
+
+       for (; i < buf_len; i++)
+               dst_buf[i] = 0;
+}
+
+/* Copy from buffer to vli.
+ * For buffers smaller than vli: fill up remaining vli with zeroes.
+ * For buffers larger than vli : copy only LSB nbytes to vli.
+ */
+void vli_copy_from_buf(u64 *dst_vli, unsigned int ndigits,
+                      const u8 *src_buf, unsigned int buf_len)
+{
+       unsigned int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+       u8 *vli = (u8 *)dst_vli;
+       int i;
+
+       for (i = 0; i < buf_len && i < nbytes; i++)
+               vli[i] = src_buf[i];
+
+       for (; i < nbytes; i++)
+               vli[i] = 0;
+}
+
 /* Returns sign of left - right. */
 static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
 {
@@ -440,6 +476,83 @@ static void vli_mod_sub(u64 *result, const u64 *left, 
const u64 *right,
                vli_add(result, result, mod, ndigits);
 }
 
+/* Computes result = input % mod.
+ * Assumes that input < mod, result != mod.
+ */
+void vli_mod(u64 *result, const u64 *input, const u64 *mod,
+            unsigned int ndigits)
+{
+       if (vli_cmp(input, mod, ndigits) >= 0)
+               vli_sub(result, input, mod, ndigits);
+       else
+               vli_set(result, input, ndigits);
+}
+
+/* Print vli in big-endian format.
+ * The bytes are printed in hex.
+ */
+void vli_print(char *vli_name, const u64 *vli, unsigned int ndigits)
+{
+       int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+       int buf_size = 2 * ECC_MAX_DIGIT_BYTES + 1;
+       unsigned char *c, buf[buf_size];
+       int i, j;
+
+       c = (unsigned char *)vli;
+
+       for (i = nbytes - 1, j = 0; i >= 0 && j < buf_size; i--, j += 2)
+               snprintf(&buf[j], 3, "%02x", *(c + i));
+
+       buf[j] = '\0';
+
+       pr_info("%20s(BigEnd)=%s\n", vli_name, buf);
+}
+
+/* Computes result = (left * right) % mod.
+ * Assumes that left < mod and right < mod, result != mod.
+ * Uses:
+ *     (a * b) % m = ((a % m) * (b % m)) % m
+ *     (a * b) % m = (a + a + ... + a) % m = b modular additions of (a % m)
+ */
+void vli_mod_mult(u64 *result, const u64 *left, const u64 *right,
+                 const u64 *mod, unsigned int ndigits)
+{
+       u64 t1[ndigits], mm[ndigits];
+       u64 aa[ndigits], bb[ndigits];
+
+       vli_clear(result, ndigits);
+       vli_set(aa, left, ndigits);
+       vli_set(bb, right, ndigits);
+       vli_set(mm, mod, ndigits);
+
+       /* aa = aa % mm */
+       vli_mod(aa, aa, mm, ndigits);
+
+       /* bb = bb % mm */
+       vli_mod(bb, bb, mm, ndigits);
+
+       while (!vli_is_zero(bb, ndigits)) {
+
+               /* if bb is odd i.e. 0th bit set then add
+                * aa i.e. result = (result + aa) % mm
+                */
+               if (vli_test_bit(bb, 0))
+                       vli_mod_add(result, result, aa, mm, ndigits);
+
+               /* bb = bb / 2 = bb >> 1 */
+               vli_rshift1(bb, ndigits);
+
+               /* aa = (aa * 2) % mm */
+               vli_sub(t1, mm, aa, ndigits);
+               if (vli_cmp(aa, t1, ndigits) == -1)
+                       /* if aa < t1 then aa = aa * 2 = aa << 1*/
+                       vli_lshift(aa, aa, 1, ndigits);
+               else
+                       /* if aa >= t1 then aa = aa - t1 */
+                       vli_sub(aa, aa, t1, ndigits);
+       }
+}
+
 /* Computes p_result = p_product % curve_p.
  * See algorithm 5 and 6 from
  * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
@@ -878,6 +991,61 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, 
u64 *curve_prime,
        vli_set(x1, t7, ndigits);
 }
 
+/* Point addition.
+ * Add 2 distinct points on elliptic curve to get a new point.
+ *
+ * P = (x1,y1)and Q = (x2, y2) then P + Q = (x3,y3) where
+ * x3 = ((y2-y1)/(x2-x1))^2 - x1 - x2
+ * y3 = ((y2-y1)/(x2-x1))(x1-x3) - y1
+ *
+ * Q => P + Q
+ */
+void ecc_point_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
+                  unsigned int ndigits)
+{
+       /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
+       u64 t5[ndigits];
+       u64 t6[ndigits];
+       u64 t7[ndigits];
+
+       /* t6 = x2 - x1 */
+       vli_mod_sub(t6, x2, x1, curve_prime, ndigits);
+       /* t6 = (x2 - x1)^2 = A */
+       vli_mod_square_fast(t6, t6, curve_prime, ndigits);
+       vli_mod_inv(t7, t6, curve_prime, ndigits);
+       /* t5 = x2 - x1 */
+       vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
+       /* t5 = (x2 - x1)^2 = A */
+       vli_mod_square_fast(t5, t5, curve_prime, ndigits);
+       /* t1 = x1*A = B = x1*(x2-x1)^2*/
+       vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
+       /* t3 = x2*A = C = x2*(x2-x1)^2*/
+       vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
+       /* t4 = y2 - y1 */
+       vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+       /* t5 = (y2 - y1)^2 = D */
+       vli_mod_square_fast(t5, y2, curve_prime, ndigits);
+
+       /* t5 = D - B = (y2 - y1)^2 - x1*(x2-x1)^2 */
+       vli_mod_sub(t5, t5, x1, curve_prime, ndigits);
+       /* t5 = D - B - C = x3 = (y2 - y1)^2 - x1*(x2-x1)^2 - x2*(x2-x1)^2*/
+       vli_mod_sub(t5, t5, x2, curve_prime, ndigits);
+
+       /* t3 = C - B = x2*(x2-x1)^2 - x1*(x2-x1)^2 */
+       vli_mod_sub(x2, x2, x1, curve_prime, ndigits);
+       /* t2 = y1*(C - B) = y1*(x2*(x2-x1)^2 - x1*(x2-x1)^2)*/
+       vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits);
+       /* t3 = B - x3 = x1*(x2-x1)^2 - x3*/
+       vli_mod_sub(x2, x1, t5, curve_prime, ndigits);
+       /* t4 = (y2 - y1)*(B - x3)  = (y2 - y1)*(x1*(x2-x1)^2 - x3)*/
+       vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits);
+       /* t4 = y3 = ((y2 - y1)*(x1*(x2-x1)^2 - x3)) - y1*/
+       vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
+
+       vli_mod_mult_fast(t5, t5, t7,  curve_prime, ndigits);
+       vli_set(x2, t5, ndigits);
+}
+
 static void ecc_point_mult(struct ecc_point *result,
                           const struct ecc_point *point, const u64 *scalar,
                           u64 *initial_z, u64 *curve_prime,
@@ -965,3 +1133,24 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int 
ndigits,
 
        return 0;
 }
+
+int ecc_is_pub_key_valid(unsigned int curve_id, unsigned int ndigits,
+                        const u8 *pub_key, unsigned int pub_key_len)
+{
+       const struct ecc_curve *curve = ecc_get_curve(curve_id);
+       int nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
+       struct ecc_point p;
+
+       if (!pub_key || pub_key_len != 2 * nbytes)
+               return -EINVAL;
+
+       p.x = (u64 *)pub_key;
+       p.y = (u64 *)(pub_key + ECC_MAX_DIGIT_BYTES);
+       p.ndigits = ndigits;
+
+       if (vli_cmp(curve->p, p.x, ndigits) != 1 ||
+           vli_cmp(curve->p, p.y, ndigits) != 1)
+               return -EINVAL;
+
+       return 0;
+}
-- 
1.7.6.3

Reply via email to