LCOV - code coverage report
Current view: top level - mpi - ec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 427 600 71.2 %
Date: 2015-11-05 17:08:00 Functions: 39 47 83.0 %

          Line data    Source code
       1             : /* ec.c -  Elliptic Curve functions
       2             :  * Copyright (C) 2007 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2013 g10 Code GmbH
       4             :  *
       5             :  * This file is part of Libgcrypt.
       6             :  *
       7             :  * Libgcrypt is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU Lesser General Public License as
       9             :  * published by the Free Software Foundation; either version 2.1 of
      10             :  * the License, or (at your option) any later version.
      11             :  *
      12             :  * Libgcrypt is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <errno.h>
      25             : 
      26             : #include "mpi-internal.h"
      27             : #include "longlong.h"
      28             : #include "g10lib.h"
      29             : #include "context.h"
      30             : #include "ec-context.h"
      31             : #include "ec-internal.h"
      32             : 
      33             : 
      34             : #define point_init(a)  _gcry_mpi_point_init ((a))
      35             : #define point_free(a)  _gcry_mpi_point_free_parts ((a))
      36             : 
      37             : 
      38             : /* Print a point using the log fucntions.  If CTX is not NULL affine
      39             :    coordinates will be printed.  */
      40             : void
      41           0 : _gcry_mpi_point_log (const char *name, mpi_point_t point, mpi_ec_t ctx)
      42             : {
      43             :   gcry_mpi_t x, y;
      44             :   char buf[100];
      45             : 
      46           0 :   if (!point)
      47             :     {
      48           0 :       snprintf (buf, sizeof buf - 1, "%s.*", name);
      49           0 :       log_mpidump (buf, NULL);
      50           0 :       return;
      51             :     }
      52           0 :   snprintf (buf, sizeof buf - 1, "%s.X", name);
      53             : 
      54           0 :   if (ctx)
      55             :     {
      56           0 :       x = mpi_new (0);
      57           0 :       y = mpi_new (0);
      58             :     }
      59           0 :   if (!ctx || _gcry_mpi_ec_get_affine (x, y, point, ctx))
      60             :     {
      61           0 :       log_mpidump (buf, point->x);
      62           0 :       buf[strlen(buf)-1] = 'Y';
      63           0 :       log_mpidump (buf, point->y);
      64           0 :       buf[strlen(buf)-1] = 'Z';
      65           0 :       log_mpidump (buf, point->z);
      66             :     }
      67             :   else
      68             :     {
      69           0 :       buf[strlen(buf)-1] = 'x';
      70           0 :       log_mpidump (buf, x);
      71           0 :       buf[strlen(buf)-1] = 'y';
      72           0 :       log_mpidump (buf, y);
      73             : 
      74             :     }
      75           0 :   if (ctx)
      76             :     {
      77           0 :       _gcry_mpi_release (x);
      78           0 :       _gcry_mpi_release (y);
      79             :     }
      80             : }
      81             : 
      82             : 
      83             : /* Create a new point option.  NBITS gives the size in bits of one
      84             :    coordinate; it is only used to pre-allocate some resources and
      85             :    might also be passed as 0 to use a default value.  */
      86             : mpi_point_t
      87          33 : _gcry_mpi_point_new (unsigned int nbits)
      88             : {
      89             :   mpi_point_t p;
      90             : 
      91             :   (void)nbits;  /* Currently not used.  */
      92             : 
      93          33 :   p = xmalloc (sizeof *p);
      94          33 :   _gcry_mpi_point_init (p);
      95          33 :   return p;
      96             : }
      97             : 
      98             : 
      99             : /* Release the point object P.  P may be NULL. */
     100             : void
     101        4923 : _gcry_mpi_point_release (mpi_point_t p)
     102             : {
     103        4923 :   if (p)
     104             :     {
     105          24 :       _gcry_mpi_point_free_parts (p);
     106          24 :       xfree (p);
     107             :     }
     108        4923 : }
     109             : 
     110             : 
     111             : /* Initialize the fields of a point object.  gcry_mpi_point_free_parts
     112             :    may be used to release the fields.  */
     113             : void
     114        8181 : _gcry_mpi_point_init (mpi_point_t p)
     115             : {
     116        8181 :   p->x = mpi_new (0);
     117        8181 :   p->y = mpi_new (0);
     118        8181 :   p->z = mpi_new (0);
     119        8181 : }
     120             : 
     121             : 
     122             : /* Release the parts of a point object. */
     123             : void
     124       13269 : _gcry_mpi_point_free_parts (mpi_point_t p)
     125             : {
     126       13269 :   mpi_free (p->x); p->x = NULL;
     127       13269 :   mpi_free (p->y); p->y = NULL;
     128       13269 :   mpi_free (p->z); p->z = NULL;
     129       13269 : }
     130             : 
     131             : 
     132             : /* Set the value from S into D.  */
     133             : static void
     134      207616 : point_set (mpi_point_t d, mpi_point_t s)
     135             : {
     136      207616 :   mpi_set (d->x, s->x);
     137      207616 :   mpi_set (d->y, s->y);
     138      207616 :   mpi_set (d->z, s->z);
     139      207616 : }
     140             : 
     141             : 
     142             : /* Set the projective coordinates from POINT into X, Y, and Z.  If a
     143             :    coordinate is not required, X, Y, or Z may be passed as NULL.  */
     144             : void
     145           6 : _gcry_mpi_point_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
     146             :                      mpi_point_t point)
     147             : {
     148           6 :   if (x)
     149           6 :     mpi_set (x, point->x);
     150           6 :   if (y)
     151           6 :     mpi_set (y, point->y);
     152           6 :   if (z)
     153           6 :     mpi_set (z, point->z);
     154           6 : }
     155             : 
     156             : 
     157             : /* Set the projective coordinates from POINT into X, Y, and Z and
     158             :    release POINT.  If a coordinate is not required, X, Y, or Z may be
     159             :    passed as NULL.  */
     160             : void
     161           9 : _gcry_mpi_point_snatch_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
     162             :                             mpi_point_t point)
     163             : {
     164           9 :   mpi_snatch (x, point->x);
     165           9 :   mpi_snatch (y, point->y);
     166           9 :   mpi_snatch (z, point->z);
     167           9 :   xfree (point);
     168           9 : }
     169             : 
     170             : 
     171             : /* Set the projective coordinates from X, Y, and Z into POINT.  If a
     172             :    coordinate is given as NULL, the value 0 is stored into point.  If
     173             :    POINT is given as NULL a new point object is allocated.  Returns
     174             :    POINT or the newly allocated point object. */
     175             : mpi_point_t
     176           6 : _gcry_mpi_point_set (mpi_point_t point,
     177             :                      gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z)
     178             : {
     179           6 :   if (!point)
     180           0 :     point = mpi_point_new (0);
     181             : 
     182           6 :   if (x)
     183           6 :     mpi_set (point->x, x);
     184             :   else
     185           0 :     mpi_clear (point->x);
     186           6 :   if (y)
     187           6 :     mpi_set (point->y, y);
     188             :   else
     189           0 :     mpi_clear (point->y);
     190           6 :   if (z)
     191           6 :     mpi_set (point->z, z);
     192             :   else
     193           0 :     mpi_clear (point->z);
     194             : 
     195           6 :   return point;
     196             : }
     197             : 
     198             : 
     199             : /* Set the projective coordinates from X, Y, and Z into POINT.  If a
     200             :    coordinate is given as NULL, the value 0 is stored into point.  If
     201             :    POINT is given as NULL a new point object is allocated.  The
     202             :    coordinates X, Y, and Z are released.  Returns POINT or the newly
     203             :    allocated point object. */
     204             : mpi_point_t
     205          12 : _gcry_mpi_point_snatch_set (mpi_point_t point,
     206             :                             gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z)
     207             : {
     208          12 :   if (!point)
     209          10 :     point = mpi_point_new (0);
     210             : 
     211          12 :   if (x)
     212          12 :     mpi_snatch (point->x, x);
     213             :   else
     214           0 :     mpi_clear (point->x);
     215          12 :   if (y)
     216          12 :     mpi_snatch (point->y, y);
     217             :   else
     218           0 :     mpi_clear (point->y);
     219          12 :   if (z)
     220          12 :     mpi_snatch (point->z, z);
     221             :   else
     222           0 :     mpi_clear (point->z);
     223             : 
     224          12 :   return point;
     225             : }
     226             : 
     227             : 
     228             : /* W = W mod P.  */
     229             : static void
     230    32774808 : ec_mod (gcry_mpi_t w, mpi_ec_t ec)
     231             : {
     232             :   if (0 && ec->dialect == ECC_DIALECT_ED25519)
     233             :     _gcry_mpi_ec_ed25519_mod (w);
     234    32774808 :   else if (ec->t.p_barrett)
     235           0 :     _gcry_mpi_mod_barrett (w, w, ec->t.p_barrett);
     236             :   else
     237    32774808 :     _gcry_mpi_mod (w, w, ec->p);
     238    32774808 : }
     239             : 
     240             : static void
     241     6223466 : ec_addm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx)
     242             : {
     243     6223466 :   mpi_add (w, u, v);
     244     6223466 :   ec_mod (w, ctx);
     245     6223466 : }
     246             : 
     247             : static void
     248    10943364 : ec_subm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ec)
     249             : {
     250             :   (void)ec;
     251    10943364 :   mpi_sub (w, u, v);
     252             :   /*ec_mod (w, ec);*/
     253    10943364 : }
     254             : 
     255             : static void
     256    24600083 : ec_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx)
     257             : {
     258    24600083 :   mpi_mul (w, u, v);
     259    24600083 :   ec_mod (w, ctx);
     260    24600083 : }
     261             : 
     262             : /* W = 2 * U mod P.  */
     263             : static void
     264     1951259 : ec_mul2 (gcry_mpi_t w, gcry_mpi_t u, mpi_ec_t ctx)
     265             : {
     266     1951259 :   mpi_lshift (w, u, 1);
     267     1951259 :   ec_mod (w, ctx);
     268     1951259 : }
     269             : 
     270             : static void
     271      187285 : ec_powm (gcry_mpi_t w, const gcry_mpi_t b, const gcry_mpi_t e,
     272             :          mpi_ec_t ctx)
     273             : {
     274      187285 :   mpi_powm (w, b, e, ctx->p);
     275             :   /* _gcry_mpi_abs (w); */
     276      187285 : }
     277             : 
     278             : 
     279             : /* Shortcut for
     280             :      ec_powm (B, B, mpi_const (MPI_C_TWO), ctx);
     281             :    for easier optimization.  */
     282             : static void
     283     8065459 : ec_pow2 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx)
     284             : {
     285             :   /* Using mpi_mul is slightly faster (at least on amd64).  */
     286             :   /* mpi_powm (w, b, mpi_const (MPI_C_TWO), ctx->p); */
     287     8065459 :   ec_mulm (w, b, b, ctx);
     288     8065459 : }
     289             : 
     290             : 
     291             : /* Shortcut for
     292             :      ec_powm (B, B, mpi_const (MPI_C_THREE), ctx);
     293             :    for easier optimization.  */
     294             : static void
     295           6 : ec_pow3 (gcry_mpi_t w, const gcry_mpi_t b, mpi_ec_t ctx)
     296             : {
     297           6 :   mpi_powm (w, b, mpi_const (MPI_C_THREE), ctx->p);
     298           6 : }
     299             : 
     300             : 
     301             : static void
     302        4894 : ec_invm (gcry_mpi_t x, gcry_mpi_t a, mpi_ec_t ctx)
     303             : {
     304        4894 :   if (!mpi_invm (x, a, ctx->p))
     305             :     {
     306           0 :       log_error ("ec_invm: inverse does not exist:\n");
     307           0 :       log_mpidump ("  a", a);
     308           0 :       log_mpidump ("  p", ctx->p);
     309             :     }
     310        4894 : }
     311             : 
     312             : 
     313             : /* Force recomputation of all helper variables.  */
     314             : void
     315        2441 : _gcry_mpi_ec_get_reset (mpi_ec_t ec)
     316             : {
     317        2441 :   ec->t.valid.a_is_pminus3 = 0;
     318        2441 :   ec->t.valid.two_inv_p = 0;
     319        2441 : }
     320             : 
     321             : 
     322             : /* Accessor for helper variable.  */
     323             : static int
     324      154639 : ec_get_a_is_pminus3 (mpi_ec_t ec)
     325             : {
     326             :   gcry_mpi_t tmp;
     327             : 
     328      154639 :   if (!ec->t.valid.a_is_pminus3)
     329             :     {
     330         325 :       ec->t.valid.a_is_pminus3 = 1;
     331         325 :       tmp = mpi_alloc_like (ec->p);
     332         325 :       mpi_sub_ui (tmp, ec->p, 3);
     333         325 :       ec->t.a_is_pminus3 = !mpi_cmp (ec->a, tmp);
     334         325 :       mpi_free (tmp);
     335             :     }
     336             : 
     337      154639 :   return ec->t.a_is_pminus3;
     338             : }
     339             : 
     340             : 
     341             : /* Accessor for helper variable.  */
     342             : static gcry_mpi_t
     343       51239 : ec_get_two_inv_p (mpi_ec_t ec)
     344             : {
     345       51239 :   if (!ec->t.valid.two_inv_p)
     346             :     {
     347         325 :       ec->t.valid.two_inv_p = 1;
     348         325 :       if (!ec->t.two_inv_p)
     349         325 :         ec->t.two_inv_p = mpi_alloc (0);
     350         325 :       ec_invm (ec->t.two_inv_p, mpi_const (MPI_C_TWO), ec);
     351             :     }
     352       51239 :   return ec->t.two_inv_p;
     353             : }
     354             : 
     355             : 
     356             : 
     357             : /* This function initialized a context for elliptic curve based on the
     358             :    field GF(p).  P is the prime specifying this field, A is the first
     359             :    coefficient.  CTX is expected to be zeroized.  */
     360             : static void
     361        2441 : ec_p_init (mpi_ec_t ctx, enum gcry_mpi_ec_models model,
     362             :            enum ecc_dialects dialect,
     363             :            int flags,
     364             :            gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
     365             : {
     366             :   int i;
     367             :   static int use_barrett;
     368             : 
     369        2441 :   if (!use_barrett)
     370             :     {
     371           8 :       if (getenv ("GCRYPT_BARRETT"))
     372           0 :         use_barrett = 1;
     373             :       else
     374           8 :         use_barrett = -1;
     375             :     }
     376             : 
     377             :   /* Fixme: Do we want to check some constraints? e.g.  a < p  */
     378             : 
     379        2441 :   ctx->model = model;
     380        2441 :   ctx->dialect = dialect;
     381        2441 :   ctx->flags = flags;
     382        2441 :   if (dialect == ECC_DIALECT_ED25519)
     383        2107 :     ctx->nbits = 256;
     384             :   else
     385         334 :     ctx->nbits = mpi_get_nbits (p);
     386        2441 :   ctx->p = mpi_copy (p);
     387        2441 :   ctx->a = mpi_copy (a);
     388        2441 :   ctx->b = mpi_copy (b);
     389             : 
     390        2441 :   ctx->t.p_barrett = use_barrett > 0? _gcry_mpi_barrett_init (ctx->p, 0):NULL;
     391             : 
     392        2441 :   _gcry_mpi_ec_get_reset (ctx);
     393             : 
     394             :   /* Allocate scratch variables.  */
     395       29292 :   for (i=0; i< DIM(ctx->t.scratch); i++)
     396       26851 :     ctx->t.scratch[i] = mpi_alloc_like (ctx->p);
     397             : 
     398             :   /* Prepare for fast reduction.  */
     399             :   /* FIXME: need a test for NIST values.  However it does not gain us
     400             :      any real advantage, for 384 bits it is actually slower than using
     401             :      mpi_mulm.  */
     402             : /*   ctx->nist_nbits = mpi_get_nbits (ctx->p); */
     403             : /*   if (ctx->nist_nbits == 192) */
     404             : /*     { */
     405             : /*       for (i=0; i < 4; i++) */
     406             : /*         ctx->s[i] = mpi_new (192); */
     407             : /*       ctx->c    = mpi_new (192*2); */
     408             : /*     } */
     409             : /*   else if (ctx->nist_nbits == 384) */
     410             : /*     { */
     411             : /*       for (i=0; i < 10; i++) */
     412             : /*         ctx->s[i] = mpi_new (384); */
     413             : /*       ctx->c    = mpi_new (384*2); */
     414             : /*     } */
     415        2441 : }
     416             : 
     417             : 
     418             : static void
     419        2441 : ec_deinit (void *opaque)
     420             : {
     421        2441 :   mpi_ec_t ctx = opaque;
     422             :   int i;
     423             : 
     424        2441 :   _gcry_mpi_barrett_free (ctx->t.p_barrett);
     425             : 
     426             :   /* Domain parameter.  */
     427        2441 :   mpi_free (ctx->p);
     428        2441 :   mpi_free (ctx->a);
     429        2441 :   mpi_free (ctx->b);
     430        2441 :   _gcry_mpi_point_release (ctx->G);
     431        2441 :   mpi_free (ctx->n);
     432        2441 :   mpi_free (ctx->h);
     433             : 
     434             :   /* The key.  */
     435        2441 :   _gcry_mpi_point_release (ctx->Q);
     436        2441 :   mpi_free (ctx->d);
     437             : 
     438             :   /* Private data of ec.c.  */
     439        2441 :   mpi_free (ctx->t.two_inv_p);
     440             : 
     441       29292 :   for (i=0; i< DIM(ctx->t.scratch); i++)
     442       26851 :     mpi_free (ctx->t.scratch[i]);
     443             : 
     444             : /*   if (ctx->nist_nbits == 192) */
     445             : /*     { */
     446             : /*       for (i=0; i < 4; i++) */
     447             : /*         mpi_free (ctx->s[i]); */
     448             : /*       mpi_free (ctx->c); */
     449             : /*     } */
     450             : /*   else if (ctx->nist_nbits == 384) */
     451             : /*     { */
     452             : /*       for (i=0; i < 10; i++) */
     453             : /*         mpi_free (ctx->s[i]); */
     454             : /*       mpi_free (ctx->c); */
     455             : /*     } */
     456        2441 : }
     457             : 
     458             : 
     459             : /* This function returns a new context for elliptic curve based on the
     460             :    field GF(p).  P is the prime specifying this field, A is the first
     461             :    coefficient, B is the second coefficient, and MODEL is the model
     462             :    for the curve.  This function is only used within Libgcrypt and not
     463             :    part of the public API.
     464             : 
     465             :    This context needs to be released using _gcry_mpi_ec_free.  */
     466             : mpi_ec_t
     467        2429 : _gcry_mpi_ec_p_internal_new (enum gcry_mpi_ec_models model,
     468             :                              enum ecc_dialects dialect,
     469             :                              int flags,
     470             :                              gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
     471             : {
     472             :   mpi_ec_t ctx;
     473             : 
     474        2429 :   ctx = xcalloc (1, sizeof *ctx);
     475        2429 :   ec_p_init (ctx, model, dialect, flags, p, a, b);
     476             : 
     477        2429 :   return ctx;
     478             : }
     479             : 
     480             : 
     481             : /* This is a variant of _gcry_mpi_ec_p_internal_new which returns an
     482             :    public context and does some error checking on the supplied
     483             :    arguments.  On success the new context is stored at R_CTX and 0 is
     484             :    returned; on error NULL is stored at R_CTX and an error code is
     485             :    returned.
     486             : 
     487             :    The context needs to be released using gcry_ctx_release.  */
     488             : gpg_err_code_t
     489          14 : _gcry_mpi_ec_p_new (gcry_ctx_t *r_ctx,
     490             :                     enum gcry_mpi_ec_models model,
     491             :                     enum ecc_dialects dialect,
     492             :                     int flags,
     493             :                     gcry_mpi_t p, gcry_mpi_t a, gcry_mpi_t b)
     494             : {
     495             :   gcry_ctx_t ctx;
     496             :   mpi_ec_t ec;
     497             : 
     498          14 :   *r_ctx = NULL;
     499          14 :   if (!p || !a)
     500           2 :     return GPG_ERR_EINVAL;
     501             : 
     502          12 :   ctx = _gcry_ctx_alloc (CONTEXT_TYPE_EC, sizeof *ec, ec_deinit);
     503          12 :   if (!ctx)
     504           0 :     return gpg_err_code_from_syserror ();
     505          12 :   ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
     506          12 :   ec_p_init (ec, model, dialect, flags, p, a, b);
     507             : 
     508          12 :   *r_ctx = ctx;
     509          12 :   return 0;
     510             : }
     511             : 
     512             : 
     513             : void
     514        2429 : _gcry_mpi_ec_free (mpi_ec_t ctx)
     515             : {
     516        2429 :   if (ctx)
     517             :     {
     518        2429 :       ec_deinit (ctx);
     519        2429 :       xfree (ctx);
     520             :     }
     521        2429 : }
     522             : 
     523             : 
     524             : gcry_mpi_t
     525          53 : _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy)
     526             : {
     527          53 :   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
     528             : 
     529          53 :   return _gcry_ecc_get_mpi (name, ec, copy);
     530             : }
     531             : 
     532             : 
     533             : gcry_mpi_point_t
     534          10 : _gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy)
     535             : {
     536          10 :   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
     537             : 
     538             :   (void)copy;  /* Not used.  */
     539             : 
     540          10 :   return _gcry_ecc_get_point (name, ec);
     541             : }
     542             : 
     543             : 
     544             : gpg_err_code_t
     545           8 : _gcry_mpi_ec_set_mpi (const char *name, gcry_mpi_t newvalue,
     546             :                       gcry_ctx_t ctx)
     547             : {
     548           8 :   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
     549             : 
     550           8 :   return _gcry_ecc_set_mpi (name, newvalue, ec);
     551             : }
     552             : 
     553             : 
     554             : gpg_err_code_t
     555           2 : _gcry_mpi_ec_set_point (const char *name, gcry_mpi_point_t newvalue,
     556             :                         gcry_ctx_t ctx)
     557             : {
     558           2 :   mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC);
     559             : 
     560           2 :   return _gcry_ecc_set_point (name, newvalue, ec);
     561             : }
     562             : 
     563             : 
     564             : /* Compute the affine coordinates from the projective coordinates in
     565             :    POINT.  Set them into X and Y.  If one coordinate is not required,
     566             :    X or Y may be passed as NULL.  CTX is the usual context. Returns: 0
     567             :    on success or !0 if POINT is at infinity.  */
     568             : int
     569        4559 : _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, mpi_point_t point,
     570             :                          mpi_ec_t ctx)
     571             : {
     572        4559 :   if (!mpi_cmp_ui (point->z, 0))
     573           0 :     return -1;
     574             : 
     575        4559 :   switch (ctx->model)
     576             :     {
     577             :     case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates.  */
     578             :       {
     579             :         gcry_mpi_t z1, z2, z3;
     580             : 
     581         356 :         z1 = mpi_new (0);
     582         356 :         z2 = mpi_new (0);
     583         356 :         ec_invm (z1, point->z, ctx);  /* z1 = z^(-1) mod p  */
     584         356 :         ec_mulm (z2, z1, z1, ctx);    /* z2 = z^(-2) mod p  */
     585             : 
     586         356 :         if (x)
     587         356 :           ec_mulm (x, point->x, z2, ctx);
     588             : 
     589         356 :         if (y)
     590             :           {
     591          49 :             z3 = mpi_new (0);
     592          49 :             ec_mulm (z3, z2, z1, ctx);      /* z3 = z^(-3) mod p  */
     593          49 :             ec_mulm (y, point->y, z3, ctx);
     594          49 :             mpi_free (z3);
     595             :           }
     596             : 
     597         356 :         mpi_free (z2);
     598         356 :         mpi_free (z1);
     599             :       }
     600         356 :       return 0;
     601             : 
     602             :     case MPI_EC_MONTGOMERY:
     603             :       {
     604           0 :         if (x)
     605           0 :           mpi_set (x, point->x);
     606             : 
     607           0 :         if (y)
     608             :           {
     609           0 :             log_fatal ("%s: Getting Y-coordinate on %s is not supported\n",
     610             :                        "_gcry_mpi_ec_get_affine", "Montgomery");
     611             :             return -1;
     612             :           }
     613             :       }
     614           0 :       return 0;
     615             : 
     616             :     case MPI_EC_EDWARDS:
     617             :       {
     618             :         gcry_mpi_t z;
     619             : 
     620        4203 :         z = mpi_new (0);
     621        4203 :         ec_invm (z, point->z, ctx);
     622             : 
     623        4203 :         if (x)
     624        4203 :           ec_mulm (x, point->x, z, ctx);
     625        4203 :         if (y)
     626        4191 :           ec_mulm (y, point->y, z, ctx);
     627             : 
     628        4203 :         _gcry_mpi_release (z);
     629             :       }
     630        4203 :       return 0;
     631             : 
     632             :     default:
     633           0 :       return -1;
     634             :     }
     635             : }
     636             : 
     637             : 
     638             : 
     639             : /*  RESULT = 2 * POINT  (Weierstrass version). */
     640             : static void
     641      154639 : dup_point_weierstrass (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
     642             : {
     643             : #define x3 (result->x)
     644             : #define y3 (result->y)
     645             : #define z3 (result->z)
     646             : #define t1 (ctx->t.scratch[0])
     647             : #define t2 (ctx->t.scratch[1])
     648             : #define t3 (ctx->t.scratch[2])
     649             : #define l1 (ctx->t.scratch[3])
     650             : #define l2 (ctx->t.scratch[4])
     651             : #define l3 (ctx->t.scratch[5])
     652             : 
     653      154639 :   if (!mpi_cmp_ui (point->y, 0) || !mpi_cmp_ui (point->z, 0))
     654             :     {
     655             :       /* P_y == 0 || P_z == 0 => [1:1:0] */
     656           0 :       mpi_set_ui (x3, 1);
     657           0 :       mpi_set_ui (y3, 1);
     658           0 :       mpi_set_ui (z3, 0);
     659             :     }
     660             :   else
     661             :     {
     662      154639 :       if (ec_get_a_is_pminus3 (ctx))  /* Use the faster case.  */
     663             :         {
     664             :           /* L1 = 3(X - Z^2)(X + Z^2) */
     665             :           /*                          T1: used for Z^2. */
     666             :           /*                          T2: used for the right term.  */
     667      121083 :           ec_pow2 (t1, point->z, ctx);
     668      121083 :           ec_subm (l1, point->x, t1, ctx);
     669      121083 :           ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx);
     670      121083 :           ec_addm (t2, point->x, t1, ctx);
     671      121083 :           ec_mulm (l1, l1, t2, ctx);
     672             :         }
     673             :       else /* Standard case. */
     674             :         {
     675             :           /* L1 = 3X^2 + aZ^4 */
     676             :           /*                          T1: used for aZ^4. */
     677       33556 :           ec_pow2 (l1, point->x, ctx);
     678       33556 :           ec_mulm (l1, l1, mpi_const (MPI_C_THREE), ctx);
     679       33556 :           ec_powm (t1, point->z, mpi_const (MPI_C_FOUR), ctx);
     680       33556 :           ec_mulm (t1, t1, ctx->a, ctx);
     681       33556 :           ec_addm (l1, l1, t1, ctx);
     682             :         }
     683             :       /* Z3 = 2YZ */
     684      154639 :       ec_mulm (z3, point->y, point->z, ctx);
     685      154639 :       ec_mul2 (z3, z3, ctx);
     686             : 
     687             :       /* L2 = 4XY^2 */
     688             :       /*                              T2: used for Y2; required later. */
     689      154639 :       ec_pow2 (t2, point->y, ctx);
     690      154639 :       ec_mulm (l2, t2, point->x, ctx);
     691      154639 :       ec_mulm (l2, l2, mpi_const (MPI_C_FOUR), ctx);
     692             : 
     693             :       /* X3 = L1^2 - 2L2 */
     694             :       /*                              T1: used for L2^2. */
     695      154639 :       ec_pow2 (x3, l1, ctx);
     696      154639 :       ec_mul2 (t1, l2, ctx);
     697      154639 :       ec_subm (x3, x3, t1, ctx);
     698             : 
     699             :       /* L3 = 8Y^4 */
     700             :       /*                              T2: taken from above. */
     701      154639 :       ec_pow2 (t2, t2, ctx);
     702      154639 :       ec_mulm (l3, t2, mpi_const (MPI_C_EIGHT), ctx);
     703             : 
     704             :       /* Y3 = L1(L2 - X3) - L3 */
     705      154639 :       ec_subm (y3, l2, x3, ctx);
     706      154639 :       ec_mulm (y3, y3, l1, ctx);
     707      154639 :       ec_subm (y3, y3, l3, ctx);
     708             :     }
     709             : 
     710             : #undef x3
     711             : #undef y3
     712             : #undef z3
     713             : #undef t1
     714             : #undef t2
     715             : #undef t3
     716             : #undef l1
     717             : #undef l2
     718             : #undef l3
     719      154639 : }
     720             : 
     721             : 
     722             : /*  RESULT = 2 * POINT  (Montgomery version). */
     723             : static void
     724           0 : dup_point_montgomery (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
     725             : {
     726             :   (void)result;
     727             :   (void)point;
     728             :   (void)ctx;
     729           0 :   log_fatal ("%s: %s not yet supported\n",
     730             :              "_gcry_mpi_ec_dup_point", "Montgomery");
     731             : }
     732             : 
     733             : 
     734             : /*  RESULT = 2 * POINT  (Twisted Edwards version). */
     735             : static void
     736     1590742 : dup_point_edwards (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
     737             : {
     738             : #define X1 (point->x)
     739             : #define Y1 (point->y)
     740             : #define Z1 (point->z)
     741             : #define X3 (result->x)
     742             : #define Y3 (result->y)
     743             : #define Z3 (result->z)
     744             : #define B (ctx->t.scratch[0])
     745             : #define C (ctx->t.scratch[1])
     746             : #define D (ctx->t.scratch[2])
     747             : #define E (ctx->t.scratch[3])
     748             : #define F (ctx->t.scratch[4])
     749             : #define H (ctx->t.scratch[5])
     750             : #define J (ctx->t.scratch[6])
     751             : 
     752             :   /* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */
     753             : 
     754             :   /* B = (X_1 + Y_1)^2  */
     755     1590742 :   ec_addm (B, X1, Y1, ctx);
     756     1590742 :   ec_pow2 (B, B, ctx);
     757             : 
     758             :   /* C = X_1^2 */
     759             :   /* D = Y_1^2 */
     760     1590742 :   ec_pow2 (C, X1, ctx);
     761     1590742 :   ec_pow2 (D, Y1, ctx);
     762             : 
     763             :   /* E = aC */
     764     1590742 :   if (ctx->dialect == ECC_DIALECT_ED25519)
     765             :     {
     766     1590742 :       mpi_set (E, C);
     767     1590742 :       _gcry_mpi_neg (E, E);
     768             :     }
     769             :   else
     770           0 :     ec_mulm (E, ctx->a, C, ctx);
     771             : 
     772             :   /* F = E + D */
     773     1590742 :   ec_addm (F, E, D, ctx);
     774             : 
     775             :   /* H = Z_1^2 */
     776     1590742 :   ec_pow2 (H, Z1, ctx);
     777             : 
     778             :   /* J = F - 2H */
     779     1590742 :   ec_mul2 (J, H, ctx);
     780     1590742 :   ec_subm (J, F, J, ctx);
     781             : 
     782             :   /* X_3 = (B - C - D) · J */
     783     1590742 :   ec_subm (X3, B, C, ctx);
     784     1590742 :   ec_subm (X3, X3, D, ctx);
     785     1590742 :   ec_mulm (X3, X3, J, ctx);
     786             : 
     787             :   /* Y_3 = F · (E - D) */
     788     1590742 :   ec_subm (Y3, E, D, ctx);
     789     1590742 :   ec_mulm (Y3, Y3, F, ctx);
     790             : 
     791             :   /* Z_3 = F · J */
     792     1590742 :   ec_mulm (Z3, F, J, ctx);
     793             : 
     794             : #undef X1
     795             : #undef Y1
     796             : #undef Z1
     797             : #undef X3
     798             : #undef Y3
     799             : #undef Z3
     800             : #undef B
     801             : #undef C
     802             : #undef D
     803             : #undef E
     804             : #undef F
     805             : #undef H
     806             : #undef J
     807     1590742 : }
     808             : 
     809             : 
     810             : /*  RESULT = 2 * POINT  */
     811             : void
     812     1745381 : _gcry_mpi_ec_dup_point (mpi_point_t result, mpi_point_t point, mpi_ec_t ctx)
     813             : {
     814     1745381 :   switch (ctx->model)
     815             :     {
     816             :     case MPI_EC_WEIERSTRASS:
     817      154639 :       dup_point_weierstrass (result, point, ctx);
     818      154639 :       break;
     819             :     case MPI_EC_MONTGOMERY:
     820           0 :       dup_point_montgomery (result, point, ctx);
     821           0 :       break;
     822             :     case MPI_EC_EDWARDS:
     823     1590742 :       dup_point_edwards (result, point, ctx);
     824     1590742 :       break;
     825             :     }
     826     1745381 : }
     827             : 
     828             : 
     829             : /* RESULT = P1 + P2  (Weierstrass version).*/
     830             : static void
     831       51245 : add_points_weierstrass (mpi_point_t result,
     832             :                         mpi_point_t p1, mpi_point_t p2,
     833             :                         mpi_ec_t ctx)
     834             : {
     835             : #define x1 (p1->x    )
     836             : #define y1 (p1->y    )
     837             : #define z1 (p1->z    )
     838             : #define x2 (p2->x    )
     839             : #define y2 (p2->y    )
     840             : #define z2 (p2->z    )
     841             : #define x3 (result->x)
     842             : #define y3 (result->y)
     843             : #define z3 (result->z)
     844             : #define l1 (ctx->t.scratch[0])
     845             : #define l2 (ctx->t.scratch[1])
     846             : #define l3 (ctx->t.scratch[2])
     847             : #define l4 (ctx->t.scratch[3])
     848             : #define l5 (ctx->t.scratch[4])
     849             : #define l6 (ctx->t.scratch[5])
     850             : #define l7 (ctx->t.scratch[6])
     851             : #define l8 (ctx->t.scratch[7])
     852             : #define l9 (ctx->t.scratch[8])
     853             : #define t1 (ctx->t.scratch[9])
     854             : #define t2 (ctx->t.scratch[10])
     855             : 
     856       51245 :   if ( (!mpi_cmp (x1, x2)) && (!mpi_cmp (y1, y2)) && (!mpi_cmp (z1, z2)) )
     857             :     {
     858             :       /* Same point; need to call the duplicate function.  */
     859           0 :       _gcry_mpi_ec_dup_point (result, p1, ctx);
     860             :     }
     861       51245 :   else if (!mpi_cmp_ui (z1, 0))
     862             :     {
     863             :       /* P1 is at infinity.  */
     864           0 :       mpi_set (x3, p2->x);
     865           0 :       mpi_set (y3, p2->y);
     866           0 :       mpi_set (z3, p2->z);
     867             :     }
     868       51245 :   else if (!mpi_cmp_ui (z2, 0))
     869             :     {
     870             :       /* P2 is at infinity.  */
     871           0 :       mpi_set (x3, p1->x);
     872           0 :       mpi_set (y3, p1->y);
     873           0 :       mpi_set (z3, p1->z);
     874             :     }
     875             :   else
     876             :     {
     877       51245 :       int z1_is_one = !mpi_cmp_ui (z1, 1);
     878       51245 :       int z2_is_one = !mpi_cmp_ui (z2, 1);
     879             : 
     880             :       /* l1 = x1 z2^2  */
     881             :       /* l2 = x2 z1^2  */
     882       51245 :       if (z2_is_one)
     883       51085 :         mpi_set (l1, x1);
     884             :       else
     885             :         {
     886         160 :           ec_pow2 (l1, z2, ctx);
     887         160 :           ec_mulm (l1, l1, x1, ctx);
     888             :         }
     889       51245 :       if (z1_is_one)
     890           0 :         mpi_set (l2, x2);
     891             :       else
     892             :         {
     893       51245 :           ec_pow2 (l2, z1, ctx);
     894       51245 :           ec_mulm (l2, l2, x2, ctx);
     895             :         }
     896             :       /* l3 = l1 - l2 */
     897       51245 :       ec_subm (l3, l1, l2, ctx);
     898             :       /* l4 = y1 z2^3  */
     899       51245 :       ec_powm (l4, z2, mpi_const (MPI_C_THREE), ctx);
     900       51245 :       ec_mulm (l4, l4, y1, ctx);
     901             :       /* l5 = y2 z1^3  */
     902       51245 :       ec_powm (l5, z1, mpi_const (MPI_C_THREE), ctx);
     903       51245 :       ec_mulm (l5, l5, y2, ctx);
     904             :       /* l6 = l4 - l5  */
     905       51245 :       ec_subm (l6, l4, l5, ctx);
     906             : 
     907       51245 :       if (!mpi_cmp_ui (l3, 0))
     908             :         {
     909           6 :           if (!mpi_cmp_ui (l6, 0))
     910             :             {
     911             :               /* P1 and P2 are the same - use duplicate function.  */
     912           0 :               _gcry_mpi_ec_dup_point (result, p1, ctx);
     913             :             }
     914             :           else
     915             :             {
     916             :               /* P1 is the inverse of P2.  */
     917           6 :               mpi_set_ui (x3, 1);
     918           6 :               mpi_set_ui (y3, 1);
     919           6 :               mpi_set_ui (z3, 0);
     920             :             }
     921             :         }
     922             :       else
     923             :         {
     924             :           /* l7 = l1 + l2  */
     925       51239 :           ec_addm (l7, l1, l2, ctx);
     926             :           /* l8 = l4 + l5  */
     927       51239 :           ec_addm (l8, l4, l5, ctx);
     928             :           /* z3 = z1 z2 l3  */
     929       51239 :           ec_mulm (z3, z1, z2, ctx);
     930       51239 :           ec_mulm (z3, z3, l3, ctx);
     931             :           /* x3 = l6^2 - l7 l3^2  */
     932       51239 :           ec_pow2 (t1, l6, ctx);
     933       51239 :           ec_pow2 (t2, l3, ctx);
     934       51239 :           ec_mulm (t2, t2, l7, ctx);
     935       51239 :           ec_subm (x3, t1, t2, ctx);
     936             :           /* l9 = l7 l3^2 - 2 x3  */
     937       51239 :           ec_mul2 (t1, x3, ctx);
     938       51239 :           ec_subm (l9, t2, t1, ctx);
     939             :           /* y3 = (l9 l6 - l8 l3^3)/2  */
     940       51239 :           ec_mulm (l9, l9, l6, ctx);
     941       51239 :           ec_powm (t1, l3, mpi_const (MPI_C_THREE), ctx); /* fixme: Use saved value*/
     942       51239 :           ec_mulm (t1, t1, l8, ctx);
     943       51239 :           ec_subm (y3, l9, t1, ctx);
     944       51239 :           ec_mulm (y3, y3, ec_get_two_inv_p (ctx), ctx);
     945             :         }
     946             :     }
     947             : 
     948             : #undef x1
     949             : #undef y1
     950             : #undef z1
     951             : #undef x2
     952             : #undef y2
     953             : #undef z2
     954             : #undef x3
     955             : #undef y3
     956             : #undef z3
     957             : #undef l1
     958             : #undef l2
     959             : #undef l3
     960             : #undef l4
     961             : #undef l5
     962             : #undef l6
     963             : #undef l7
     964             : #undef l8
     965             : #undef l9
     966             : #undef t1
     967             : #undef t2
     968       51245 : }
     969             : 
     970             : 
     971             : /* RESULT = P1 + P2  (Montgomery version).*/
     972             : static void
     973           0 : add_points_montgomery (mpi_point_t result,
     974             :                        mpi_point_t p1, mpi_point_t p2,
     975             :                        mpi_ec_t ctx)
     976             : {
     977             :   (void)result;
     978             :   (void)p1;
     979             :   (void)p2;
     980             :   (void)ctx;
     981           0 :   log_fatal ("%s: %s not yet supported\n",
     982             :              "_gcry_mpi_ec_add_points", "Montgomery");
     983             : }
     984             : 
     985             : 
     986             : /* RESULT = P1 + P2  (Twisted Edwards version).*/
     987             : static void
     988      927932 : add_points_edwards (mpi_point_t result,
     989             :                     mpi_point_t p1, mpi_point_t p2,
     990             :                     mpi_ec_t ctx)
     991             : {
     992             : #define X1 (p1->x)
     993             : #define Y1 (p1->y)
     994             : #define Z1 (p1->z)
     995             : #define X2 (p2->x)
     996             : #define Y2 (p2->y)
     997             : #define Z2 (p2->z)
     998             : #define X3 (result->x)
     999             : #define Y3 (result->y)
    1000             : #define Z3 (result->z)
    1001             : #define A (ctx->t.scratch[0])
    1002             : #define B (ctx->t.scratch[1])
    1003             : #define C (ctx->t.scratch[2])
    1004             : #define D (ctx->t.scratch[3])
    1005             : #define E (ctx->t.scratch[4])
    1006             : #define F (ctx->t.scratch[5])
    1007             : #define G (ctx->t.scratch[6])
    1008             : #define tmp (ctx->t.scratch[7])
    1009             : 
    1010             :   /* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3)  */
    1011             : 
    1012             :   /* A = Z1 · Z2 */
    1013      927932 :   ec_mulm (A, Z1, Z2, ctx);
    1014             : 
    1015             :   /* B = A^2 */
    1016      927932 :   ec_pow2 (B, A, ctx);
    1017             : 
    1018             :   /* C = X1 · X2 */
    1019      927932 :   ec_mulm (C, X1, X2, ctx);
    1020             : 
    1021             :   /* D = Y1 · Y2 */
    1022      927932 :   ec_mulm (D, Y1, Y2, ctx);
    1023             : 
    1024             :   /* E = d · C · D */
    1025      927932 :   ec_mulm (E, ctx->b, C, ctx);
    1026      927932 :   ec_mulm (E, E, D, ctx);
    1027             : 
    1028             :   /* F = B - E */
    1029      927932 :   ec_subm (F, B, E, ctx);
    1030             : 
    1031             :   /* G = B + E */
    1032      927932 :   ec_addm (G, B, E, ctx);
    1033             : 
    1034             :   /* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */
    1035      927932 :   ec_addm (tmp, X1, Y1, ctx);
    1036      927932 :   ec_addm (X3, X2, Y2, ctx);
    1037      927932 :   ec_mulm (X3, X3, tmp, ctx);
    1038      927932 :   ec_subm (X3, X3, C, ctx);
    1039      927932 :   ec_subm (X3, X3, D, ctx);
    1040      927932 :   ec_mulm (X3, X3, F, ctx);
    1041      927932 :   ec_mulm (X3, X3, A, ctx);
    1042             : 
    1043             :   /* Y_3 = A · G · (D - aC) */
    1044      927932 :   if (ctx->dialect == ECC_DIALECT_ED25519)
    1045             :     {
    1046             :       /* Using ec_addm (Y3, D, C, ctx) is possible but a litte bit
    1047             :          slower because a subm does currently skip the mod step.  */
    1048      927932 :       mpi_set (Y3, C);
    1049      927932 :       _gcry_mpi_neg (Y3, Y3);
    1050      927932 :       ec_subm (Y3, D, Y3, ctx);
    1051             :     }
    1052             :   else
    1053             :     {
    1054           0 :       ec_mulm (Y3, ctx->a, C, ctx);
    1055           0 :       ec_subm (Y3, D, Y3, ctx);
    1056             :     }
    1057      927932 :   ec_mulm (Y3, Y3, G, ctx);
    1058      927932 :   ec_mulm (Y3, Y3, A, ctx);
    1059             : 
    1060             :   /* Z_3 = F · G */
    1061      927932 :   ec_mulm (Z3, F, G, ctx);
    1062             : 
    1063             : 
    1064             : #undef X1
    1065             : #undef Y1
    1066             : #undef Z1
    1067             : #undef X2
    1068             : #undef Y2
    1069             : #undef Z2
    1070             : #undef X3
    1071             : #undef Y3
    1072             : #undef Z3
    1073             : #undef A
    1074             : #undef B
    1075             : #undef C
    1076             : #undef D
    1077             : #undef E
    1078             : #undef F
    1079             : #undef G
    1080             : #undef tmp
    1081      927932 : }
    1082             : 
    1083             : 
    1084             : /* Compute a step of Montgomery Ladder (only use X and Z in the point).
    1085             :    Inputs:  P1, P2, and x-coordinate of DIF = P1 - P1.
    1086             :    Outputs: PRD = 2 * P1 and  SUM = P1 + P2. */
    1087             : static void
    1088           0 : montgomery_ladder (mpi_point_t prd, mpi_point_t sum,
    1089             :                    mpi_point_t p1, mpi_point_t p2, gcry_mpi_t dif_x,
    1090             :                    mpi_ec_t ctx)
    1091             : {
    1092           0 :   ec_addm (sum->x, p2->x, p2->z, ctx);
    1093           0 :   ec_subm (p2->z, p2->x, p2->z, ctx);
    1094           0 :   ec_addm (prd->x, p1->x, p1->z, ctx);
    1095           0 :   ec_subm (p1->z, p1->x, p1->z, ctx);
    1096           0 :   ec_mulm (p2->x, p1->z, sum->x, ctx);
    1097           0 :   ec_mulm (p2->z, prd->x, p2->z, ctx);
    1098           0 :   ec_pow2 (p1->x, prd->x, ctx);
    1099           0 :   ec_pow2 (p1->z, p1->z, ctx);
    1100           0 :   ec_addm (sum->x, p2->x, p2->z, ctx);
    1101           0 :   ec_subm (p2->z, p2->x, p2->z, ctx);
    1102           0 :   ec_mulm (prd->x, p1->x, p1->z, ctx);
    1103           0 :   ec_subm (p1->z, p1->x, p1->z, ctx);
    1104           0 :   ec_pow2 (sum->x, sum->x, ctx);
    1105           0 :   ec_pow2 (sum->z, p2->z, ctx);
    1106           0 :   ec_mulm (prd->z, p1->z, ctx->a, ctx); /* CTX->A: (a-2)/4 */
    1107           0 :   ec_mulm (sum->z, sum->z, dif_x, ctx);
    1108           0 :   ec_addm (prd->z, p1->x, prd->z, ctx);
    1109           0 :   ec_mulm (prd->z, prd->z, p1->z, ctx);
    1110           0 : }
    1111             : 
    1112             : 
    1113             : /* RESULT = P1 + P2 */
    1114             : void
    1115      979177 : _gcry_mpi_ec_add_points (mpi_point_t result,
    1116             :                          mpi_point_t p1, mpi_point_t p2,
    1117             :                          mpi_ec_t ctx)
    1118             : {
    1119      979177 :   switch (ctx->model)
    1120             :     {
    1121             :     case MPI_EC_WEIERSTRASS:
    1122       51245 :       add_points_weierstrass (result, p1, p2, ctx);
    1123       51245 :       break;
    1124             :     case MPI_EC_MONTGOMERY:
    1125           0 :       add_points_montgomery (result, p1, p2, ctx);
    1126           0 :       break;
    1127             :     case MPI_EC_EDWARDS:
    1128      927932 :       add_points_edwards (result, p1, p2, ctx);
    1129      927932 :       break;
    1130             :     }
    1131      979177 : }
    1132             : 
    1133             : 
    1134             : /* RESULT = P1 - P2  (Weierstrass version).*/
    1135             : static void
    1136           0 : sub_points_weierstrass (mpi_point_t result,
    1137             :                         mpi_point_t p1, mpi_point_t p2,
    1138             :                         mpi_ec_t ctx)
    1139             : {
    1140             :   (void)result;
    1141             :   (void)p1;
    1142             :   (void)p2;
    1143             :   (void)ctx;
    1144           0 :   log_fatal ("%s: %s not yet supported\n",
    1145             :              "_gcry_mpi_ec_sub_points", "Weierstrass");
    1146             : }
    1147             : 
    1148             : 
    1149             : /* RESULT = P1 - P2  (Montgomery version).*/
    1150             : static void
    1151           0 : sub_points_montgomery (mpi_point_t result,
    1152             :                        mpi_point_t p1, mpi_point_t p2,
    1153             :                        mpi_ec_t ctx)
    1154             : {
    1155             :   (void)result;
    1156             :   (void)p1;
    1157             :   (void)p2;
    1158             :   (void)ctx;
    1159           0 :   log_fatal ("%s: %s not yet supported\n",
    1160             :              "_gcry_mpi_ec_sub_points", "Montgomery");
    1161             : }
    1162             : 
    1163             : 
    1164             : /* RESULT = P1 - P2  (Twisted Edwards version).*/
    1165             : static void
    1166           0 : sub_points_edwards (mpi_point_t result,
    1167             :                     mpi_point_t p1, mpi_point_t p2,
    1168             :                     mpi_ec_t ctx)
    1169             : {
    1170           0 :   mpi_point_t p2i = _gcry_mpi_point_new (0);
    1171           0 :   point_set (p2i, p2);
    1172           0 :   _gcry_mpi_neg (p2i->x, p2i->x);
    1173           0 :   add_points_edwards (result, p1, p2i, ctx);
    1174           0 :   _gcry_mpi_point_release (p2i);
    1175           0 : }
    1176             : 
    1177             : 
    1178             : /* RESULT = P1 - P2 */
    1179             : void
    1180           0 : _gcry_mpi_ec_sub_points (mpi_point_t result,
    1181             :                          mpi_point_t p1, mpi_point_t p2,
    1182             :                          mpi_ec_t ctx)
    1183             : {
    1184           0 :   switch (ctx->model)
    1185             :     {
    1186             :     case MPI_EC_WEIERSTRASS:
    1187           0 :       sub_points_weierstrass (result, p1, p2, ctx);
    1188           0 :       break;
    1189             :     case MPI_EC_MONTGOMERY:
    1190           0 :       sub_points_montgomery (result, p1, p2, ctx);
    1191           0 :       break;
    1192             :     case MPI_EC_EDWARDS:
    1193           0 :       sub_points_edwards (result, p1, p2, ctx);
    1194           0 :       break;
    1195             :     }
    1196           0 : }
    1197             : 
    1198             : 
    1199             : /* Scalar point multiplication - the main function for ECC.  If takes
    1200             :    an integer SCALAR and a POINT as well as the usual context CTX.
    1201             :    RESULT will be set to the resulting point. */
    1202             : void
    1203        4666 : _gcry_mpi_ec_mul_point (mpi_point_t result,
    1204             :                         gcry_mpi_t scalar, mpi_point_t point,
    1205             :                         mpi_ec_t ctx)
    1206             : {
    1207             :   gcry_mpi_t x1, y1, z1, k, h, yy;
    1208             :   unsigned int i, loops;
    1209             :   mpi_point_struct p1, p2, p1inv;
    1210             : 
    1211        4666 :   if (ctx->model == MPI_EC_EDWARDS)
    1212             :     {
    1213             :       /* Simple left to right binary method.  GECC Algorithm 3.27 */
    1214             :       unsigned int nbits;
    1215             :       int j;
    1216             : 
    1217        4173 :       nbits = mpi_get_nbits (scalar);
    1218        4173 :       mpi_set_ui (result->x, 0);
    1219        4173 :       mpi_set_ui (result->y, 1);
    1220        4173 :       mpi_set_ui (result->z, 1);
    1221             : 
    1222        4173 :       if (mpi_is_secure (scalar))
    1223        1036 :         {
    1224             :           /* If SCALAR is in secure memory we assume that it is the
    1225             :              secret key we use constant time operation.  */
    1226             :           mpi_point_struct tmppnt;
    1227             : 
    1228        1036 :           point_init (&tmppnt);
    1229      265203 :           for (j=nbits-1; j >= 0; j--)
    1230             :             {
    1231      264167 :               _gcry_mpi_ec_dup_point (result, result, ctx);
    1232      264167 :               _gcry_mpi_ec_add_points (&tmppnt, result, point, ctx);
    1233      264167 :               if (mpi_test_bit (scalar, j))
    1234      131184 :                 point_set (result, &tmppnt);
    1235             :             }
    1236        1036 :           point_free (&tmppnt);
    1237             :         }
    1238             :       else
    1239             :         {
    1240     1329712 :           for (j=nbits-1; j >= 0; j--)
    1241             :             {
    1242     1326575 :               _gcry_mpi_ec_dup_point (result, result, ctx);
    1243     1326575 :               if (mpi_test_bit (scalar, j))
    1244      662722 :                 _gcry_mpi_ec_add_points (result, result, point, ctx);
    1245             :             }
    1246             :         }
    1247        8346 :       return;
    1248             :     }
    1249         493 :   else if (ctx->model == MPI_EC_MONTGOMERY)
    1250             :     {
    1251             :       unsigned int nbits;
    1252             :       int j;
    1253             :       mpi_point_struct p1_, p2_;
    1254             :       mpi_point_t q1, q2, prd, sum;
    1255             :       unsigned long sw;
    1256             :       size_t nlimbs;
    1257             : 
    1258             :       /* Compute scalar point multiplication with Montgomery Ladder.
    1259             :          Note that we don't use Y-coordinate in the points at all.
    1260             :          RESULT->Y will be filled by zero.  */
    1261             : 
    1262           0 :       nbits = mpi_get_nbits (scalar);
    1263           0 :       point_init (&p1);
    1264           0 :       point_init (&p2);
    1265           0 :       point_init (&p1_);
    1266           0 :       point_init (&p2_);
    1267           0 :       mpi_set_ui (p1.x, 1);
    1268           0 :       mpi_free (p2.x);
    1269           0 :       p2.x  = mpi_copy (point->x);
    1270           0 :       mpi_set_ui (p2.z, 1);
    1271             : 
    1272           0 :       nlimbs = 2*(nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB+1;
    1273           0 :       mpi_resize (p1.x, nlimbs);
    1274           0 :       mpi_resize (p1.z, nlimbs);
    1275           0 :       mpi_resize (p2.x, nlimbs);
    1276           0 :       mpi_resize (p2.z, nlimbs);
    1277           0 :       mpi_resize (p1_.x, nlimbs);
    1278           0 :       mpi_resize (p1_.z, nlimbs);
    1279           0 :       mpi_resize (p2_.x, nlimbs);
    1280           0 :       mpi_resize (p2_.z, nlimbs);
    1281             : 
    1282           0 :       q1 = &p1;
    1283           0 :       q2 = &p2;
    1284           0 :       prd = &p1_;
    1285           0 :       sum = &p2_;
    1286             : 
    1287           0 :       for (j=nbits-1; j >= 0; j--)
    1288             :         {
    1289             :           mpi_point_t t;
    1290             : 
    1291           0 :           sw = mpi_test_bit (scalar, j);
    1292           0 :           mpi_swap_cond (q1->x, q2->x, sw);
    1293           0 :           mpi_swap_cond (q1->z, q2->z, sw);
    1294           0 :           montgomery_ladder (prd, sum, q1, q2, point->x, ctx);
    1295           0 :           mpi_swap_cond (prd->x, sum->x, sw);
    1296           0 :           mpi_swap_cond (prd->z, sum->z, sw);
    1297           0 :           t = q1;  q1 = prd;  prd = t;
    1298           0 :           t = q2;  q2 = sum;  sum = t;
    1299             :         }
    1300             : 
    1301           0 :       mpi_clear (result->y);
    1302           0 :       sw = (nbits & 1);
    1303           0 :       mpi_swap_cond (p1.x, p1_.x, sw);
    1304           0 :       mpi_swap_cond (p1.z, p1_.z, sw);
    1305             : 
    1306           0 :       if (p1.z->nlimbs == 0)
    1307             :         {
    1308           0 :           mpi_set_ui (result->x, 1);
    1309           0 :           mpi_set_ui (result->z, 0);
    1310             :         }
    1311             :       else
    1312             :         {
    1313           0 :           z1 = mpi_new (0);
    1314           0 :           ec_invm (z1, p1.z, ctx);
    1315           0 :           ec_mulm (result->x, p1.x, z1, ctx);
    1316           0 :           mpi_set_ui (result->z, 1);
    1317           0 :           mpi_free (z1);
    1318             :         }
    1319             : 
    1320           0 :       point_free (&p1);
    1321           0 :       point_free (&p2);
    1322           0 :       point_free (&p1_);
    1323           0 :       point_free (&p2_);
    1324           0 :       return;
    1325             :     }
    1326             : 
    1327         493 :   x1 = mpi_alloc_like (ctx->p);
    1328         493 :   y1 = mpi_alloc_like (ctx->p);
    1329         493 :   h  = mpi_alloc_like (ctx->p);
    1330         493 :   k  = mpi_copy (scalar);
    1331         493 :   yy = mpi_copy (point->y);
    1332             : 
    1333         493 :   if ( mpi_has_sign (k) )
    1334             :     {
    1335           0 :       k->sign = 0;
    1336           0 :       ec_invm (yy, yy, ctx);
    1337             :     }
    1338             : 
    1339         493 :   if (!mpi_cmp_ui (point->z, 1))
    1340             :     {
    1341         488 :       mpi_set (x1, point->x);
    1342         488 :       mpi_set (y1, yy);
    1343             :     }
    1344             :   else
    1345             :     {
    1346             :       gcry_mpi_t z2, z3;
    1347             : 
    1348           5 :       z2 = mpi_alloc_like (ctx->p);
    1349           5 :       z3 = mpi_alloc_like (ctx->p);
    1350           5 :       ec_mulm (z2, point->z, point->z, ctx);
    1351           5 :       ec_mulm (z3, point->z, z2, ctx);
    1352           5 :       ec_invm (z2, z2, ctx);
    1353           5 :       ec_mulm (x1, point->x, z2, ctx);
    1354           5 :       ec_invm (z3, z3, ctx);
    1355           5 :       ec_mulm (y1, yy, z3, ctx);
    1356           5 :       mpi_free (z2);
    1357           5 :       mpi_free (z3);
    1358             :     }
    1359         493 :   z1 = mpi_copy (mpi_const (MPI_C_ONE));
    1360             : 
    1361         493 :   mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */
    1362         493 :   loops = mpi_get_nbits (h);
    1363         493 :   if (loops < 2)
    1364             :     {
    1365             :       /* If SCALAR is zero, the above mpi_mul sets H to zero and thus
    1366             :          LOOPs will be zero.  To avoid an underflow of I in the main
    1367             :          loop we set LOOP to 2 and the result to (0,0,0).  */
    1368           1 :       loops = 2;
    1369           1 :       mpi_clear (result->x);
    1370           1 :       mpi_clear (result->y);
    1371           1 :       mpi_clear (result->z);
    1372             :     }
    1373             :   else
    1374             :     {
    1375         492 :       mpi_set (result->x, point->x);
    1376         492 :       mpi_set (result->y, yy);
    1377         492 :       mpi_set (result->z, point->z);
    1378             :     }
    1379         493 :   mpi_free (yy); yy = NULL;
    1380             : 
    1381         493 :   p1.x = x1; x1 = NULL;
    1382         493 :   p1.y = y1; y1 = NULL;
    1383         493 :   p1.z = z1; z1 = NULL;
    1384         493 :   point_init (&p2);
    1385         493 :   point_init (&p1inv);
    1386             : 
    1387      155132 :   for (i=loops-2; i > 0; i--)
    1388             :     {
    1389      154639 :       _gcry_mpi_ec_dup_point (result, result, ctx);
    1390      154639 :       if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0)
    1391             :         {
    1392       25738 :           point_set (&p2, result);
    1393       25738 :           _gcry_mpi_ec_add_points (result, &p2, &p1, ctx);
    1394             :         }
    1395      154639 :       if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1)
    1396             :         {
    1397       25347 :           point_set (&p2, result);
    1398             :           /* Invert point: y = p - y mod p  */
    1399       25347 :           point_set (&p1inv, &p1);
    1400       25347 :           ec_subm (p1inv.y, ctx->p, p1inv.y, ctx);
    1401       25347 :           _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx);
    1402             :         }
    1403             :     }
    1404             : 
    1405         493 :   point_free (&p1);
    1406         493 :   point_free (&p2);
    1407         493 :   point_free (&p1inv);
    1408         493 :   mpi_free (h);
    1409         493 :   mpi_free (k);
    1410             : }
    1411             : 
    1412             : 
    1413             : /* Return true if POINT is on the curve described by CTX.  */
    1414             : int
    1415        1063 : _gcry_mpi_ec_curve_point (gcry_mpi_point_t point, mpi_ec_t ctx)
    1416             : {
    1417        1063 :   int res = 0;
    1418             :   gcry_mpi_t x, y, w;
    1419             : 
    1420        1063 :   x = mpi_new (0);
    1421        1063 :   y = mpi_new (0);
    1422        1063 :   w = mpi_new (0);
    1423             : 
    1424        1063 :   switch (ctx->model)
    1425             :     {
    1426             :     case MPI_EC_WEIERSTRASS:
    1427             :       {
    1428           6 :         gcry_mpi_t xxx = mpi_new (0);
    1429             : 
    1430           6 :         if (_gcry_mpi_ec_get_affine (x, y, point, ctx))
    1431           0 :           return 0;
    1432             : 
    1433             :         /* y^2 == x^3 + a·x + b */
    1434           6 :         ec_pow2 (y, y, ctx);
    1435             : 
    1436           6 :         ec_pow3 (xxx, x, ctx);
    1437           6 :         ec_mulm (w, ctx->a, x, ctx);
    1438           6 :         ec_addm (w, w, ctx->b, ctx);
    1439           6 :         ec_addm (w, w, xxx, ctx);
    1440             : 
    1441           6 :         if (!mpi_cmp (y, w))
    1442           6 :           res = 1;
    1443             : 
    1444           6 :         _gcry_mpi_release (xxx);
    1445             :       }
    1446           6 :       break;
    1447             :     case MPI_EC_MONTGOMERY:
    1448             :       {
    1449             : #define xx y
    1450             :         /* With Montgomery curve, only X-coordinate is valid.  */
    1451           0 :         if (_gcry_mpi_ec_get_affine (x, NULL, point, ctx))
    1452           0 :           return 0;
    1453             : 
    1454             :         /* The equation is: b * y^2 == x^3 + a · x^2 + x */
    1455             :         /* We check if right hand is quadratic residue or not by
    1456             :            Euler's criterion.  */
    1457             :         /* CTX->A has (a-2)/4 and CTX->B has b^-1 */
    1458           0 :         ec_mulm (w, ctx->a, mpi_const (MPI_C_FOUR), ctx);
    1459           0 :         ec_addm (w, w, mpi_const (MPI_C_TWO), ctx);
    1460           0 :         ec_mulm (w, w, x, ctx);
    1461           0 :         ec_pow2 (xx, x, ctx);
    1462           0 :         ec_addm (w, w, xx, ctx);
    1463           0 :         ec_addm (w, w, mpi_const (MPI_C_ONE), ctx);
    1464           0 :         ec_mulm (w, w, x, ctx);
    1465           0 :         ec_mulm (w, w, ctx->b, ctx);
    1466             : #undef xx
    1467             :         /* Compute Euler's criterion: w^(p-1)/2 */
    1468             : #define p_minus1 y
    1469           0 :         ec_subm (p_minus1, ctx->p, mpi_const (MPI_C_ONE), ctx);
    1470           0 :         mpi_rshift (p_minus1, p_minus1, 1);
    1471           0 :         ec_powm (w, w, p_minus1, ctx);
    1472             : 
    1473           0 :         res = !mpi_cmp_ui (w, 1);
    1474             : #undef p_minus1
    1475             :       }
    1476           0 :       break;
    1477             :     case MPI_EC_EDWARDS:
    1478             :       {
    1479        1057 :         if (_gcry_mpi_ec_get_affine (x, y, point, ctx))
    1480           0 :           return 0;
    1481             : 
    1482             :         /* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */
    1483        1057 :         ec_pow2 (x, x, ctx);
    1484        1057 :         ec_pow2 (y, y, ctx);
    1485        1057 :         if (ctx->dialect == ECC_DIALECT_ED25519)
    1486             :           {
    1487        1057 :             mpi_set (w, x);
    1488        1057 :             _gcry_mpi_neg (w, w);
    1489             :           }
    1490             :         else
    1491           0 :           ec_mulm (w, ctx->a, x, ctx);
    1492        1057 :         ec_addm (w, w, y, ctx);
    1493        1057 :         ec_subm (w, w, mpi_const (MPI_C_ONE), ctx);
    1494        1057 :         ec_mulm (x, x, y, ctx);
    1495        1057 :         ec_mulm (x, x, ctx->b, ctx);
    1496        1057 :         ec_subm (w, w, x, ctx);
    1497        1057 :         if (!mpi_cmp_ui (w, 0))
    1498        1057 :           res = 1;
    1499             :       }
    1500        1057 :       break;
    1501             :     }
    1502             : 
    1503        1063 :   _gcry_mpi_release (w);
    1504        1063 :   _gcry_mpi_release (x);
    1505        1063 :   _gcry_mpi_release (y);
    1506             : 
    1507        1063 :   return res;
    1508             : }

Generated by: LCOV version 1.11