1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 #include "tomcrypt_private.h"
5 
6 /* ### Point doubling in Jacobian coordinate system ###
7  *
8  * let us have a curve:                 y^2 = x^3 + a*x + b
9  * in Jacobian coordinates it becomes:  y^2 = x^3 + a*x*z^4 + b*z^6
10  *
11  * The doubling of P = (Xp, Yp, Zp) is given by R = (Xr, Yr, Zr) where:
12  * Xr = M^2 - 2*S
13  * Yr = M * (S - Xr) - 8*T
14  * Zr = 2 * Yp * Zp
15  *
16  * M = 3 * Xp^2 + a*Zp^4
17  * T = Yp^4
18  * S = 4 * Xp * Yp^2
19  *
20  * SPECIAL CASE: when a == -3 we can compute M as
21  * M = 3 * (Xp^2 - Zp^4) = 3 * (Xp + Zp^2) * (Xp - Zp^2)
22  */
23 
24 /**
25   @file ltc_ecc_projective_dbl_point.c
26   ECC Crypto, Tom St Denis
27 */
28 
29 #if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_DESC))
30 
31 /**
32    Double an ECC point
33    @param P   The point to double
34    @param R   [out] The destination of the double
35    @param ma  ECC curve parameter a in montgomery form
36    @param modulus  The modulus of the field the ECC curve is in
37    @param mp       The "b" value from montgomery_setup()
38    @return CRYPT_OK on success
39 */
ltc_ecc_projective_dbl_point(const ecc_point * P,ecc_point * R,void * ma,void * modulus,void * mp)40 int ltc_ecc_projective_dbl_point(const ecc_point *P, ecc_point *R, void *ma, void *modulus, void *mp)
41 {
42    void *t1, *t2;
43    int   err, inf;
44 
45    LTC_ARGCHK(P       != NULL);
46    LTC_ARGCHK(R       != NULL);
47    LTC_ARGCHK(modulus != NULL);
48    LTC_ARGCHK(mp      != NULL);
49 
50    if ((err = mp_init_multi(&t1, &t2, LTC_NULL)) != CRYPT_OK) {
51       return err;
52    }
53 
54    if (P != R) {
55       if ((err = ltc_ecc_copy_point(P, R)) != CRYPT_OK)                           { goto done; }
56    }
57 
58    if ((err = ltc_ecc_is_point_at_infinity(P, modulus, &inf)) != CRYPT_OK) return err;
59    if (inf) {
60       /* if P is point at infinity >> Result = point at infinity */
61       err = ltc_ecc_set_point_xyz(1, 1, 0, R);
62       goto done;
63    }
64 
65    /* t1 = Z * Z */
66    if ((err = mp_sqr(R->z, t1)) != CRYPT_OK)                                      { goto done; }
67    if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)                 { goto done; }
68    /* Z = Y * Z */
69    if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK)                              { goto done; }
70    if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK)               { goto done; }
71    /* Z = 2Z */
72    if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK)                              { goto done; }
73    if (mp_cmp(R->z, modulus) != LTC_MP_LT) {
74       if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK)                        { goto done; }
75    }
76 
77    if (ma == NULL) { /* special case for curves with a == -3 (10% faster than general case) */
78       /* T2 = X - T1 */
79       if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK)                               { goto done; }
80       if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
81          if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                         { goto done; }
82       }
83       /* T1 = X + T1 */
84       if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK)                               { goto done; }
85       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
86          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
87       }
88       /* T2 = T1 * T2 */
89       if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK)                                 { goto done; }
90       if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
91       /* T1 = 2T2 */
92       if ((err = mp_add(t2, t2, t1)) != CRYPT_OK)                                 { goto done; }
93       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
94          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
95       }
96       /* T1 = T1 + T2 */
97       if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                 { goto done; }
98       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
99          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
100       }
101    }
102    else {
103       /* T2 = T1 * T1 */
104       if ((err = mp_sqr(t1, t2)) != CRYPT_OK)                                     { goto done; }
105       if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
106       /* T1 = T2 * a */
107       if ((err = mp_mul(t2, ma, t1)) != CRYPT_OK)                                 { goto done; }
108       if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
109       /* T2 = X * X */
110       if ((err = mp_sqr(R->x, t2)) != CRYPT_OK)                                   { goto done; }
111       if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
112       /* T1 = T2 + T1 */
113       if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                 { goto done; }
114       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
115          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
116       }
117       /* T1 = T2 + T1 */
118       if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                 { goto done; }
119       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
120          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
121       }
122       /* T1 = T2 + T1 */
123       if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                 { goto done; }
124       if (mp_cmp(t1, modulus) != LTC_MP_LT) {
125          if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
126       }
127    }
128 
129    /* Y = 2Y */
130    if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK)                              { goto done; }
131    if (mp_cmp(R->y, modulus) != LTC_MP_LT) {
132       if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
133    }
134    /* Y = Y * Y */
135    if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK)                                    { goto done; }
136    if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
137    /* T2 = Y * Y */
138    if ((err = mp_sqr(R->y, t2)) != CRYPT_OK)                                      { goto done; }
139    if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
140    /* T2 = T2/2 */
141    if (mp_isodd(t2)) {
142       if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
143    }
144    if ((err = mp_div_2(t2, t2)) != CRYPT_OK)                                      { goto done; }
145    /* Y = Y * X */
146    if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
147    if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
148 
149    /* X  = T1 * T1 */
150    if ((err = mp_sqr(t1, R->x)) != CRYPT_OK)                                      { goto done; }
151    if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK)               { goto done; }
152    /* X = X - Y */
153    if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
154    if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
155       if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
156    }
157    /* X = X - Y */
158    if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
159    if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
160       if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
161    }
162 
163    /* Y = Y - X */
164    if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
165    if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
166       if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
167    }
168    /* Y = Y * T1 */
169    if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK)                                { goto done; }
170    if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
171    /* Y = Y - T2 */
172    if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK)                                { goto done; }
173    if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
174       if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
175    }
176 
177    err = CRYPT_OK;
178 done:
179    mp_clear_multi(t2, t1, LTC_NULL);
180    return err;
181 }
182 #endif
183