1 /*
2  * Copyright (c) 2024, The TrustedFirmware-M Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 
9 #include "cc3xx_ec_weierstrass.h"
10 
11 #include "cc3xx_ec_projective_point.h"
12 #include "cc3xx_config.h"
13 
14 #include <assert.h>
15 
16 #include "fatal_error.h"
17 
cc3xx_lowlevel_ec_weierstrass_validate_point(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p)18 bool cc3xx_lowlevel_ec_weierstrass_validate_point(cc3xx_ec_curve_t *curve,
19                                                   cc3xx_ec_point_affine *p)
20 {
21     cc3xx_err_t err;
22     bool validate_succeeded = false;
23     cc3xx_pka_reg_id_t equation_left_side = cc3xx_lowlevel_pka_allocate_reg();
24     cc3xx_pka_reg_id_t equation_right_side = cc3xx_lowlevel_pka_allocate_reg();
25     cc3xx_pka_reg_id_t temp = cc3xx_lowlevel_pka_allocate_reg();
26     cc3xx_ec_point_affine foo = cc3xx_lowlevel_ec_allocate_point();
27 
28     /* Y^2 */
29     cc3xx_lowlevel_pka_mod_exp_si(p->y, 2, equation_left_side);
30 
31     /* X^3 + aX + b */
32     cc3xx_lowlevel_pka_mod_exp_si(p->x, 3, equation_right_side);
33     cc3xx_lowlevel_pka_mod_mul(p->x, curve->param_a, temp);
34     cc3xx_lowlevel_pka_mod_add(equation_right_side, temp, equation_right_side);
35     cc3xx_lowlevel_pka_mod_add(equation_right_side, curve->param_b,
36                                equation_right_side);
37 
38     validate_succeeded = cc3xx_lowlevel_pka_are_equal(equation_left_side,
39                                                       equation_right_side);
40 
41     if (curve->cofactor != 1) {
42         /* This performs affine-to-projective conversion, which includes a check
43          * that that nP != infinity in the corresponding projective to affine
44          * conversion. The result of the multiplication isn't used.
45          */
46         err = cc3xx_lowlevel_ec_weierstrass_multipy_point_by_scalar(curve, p,
47                                                                     curve->order,
48                                                                     &foo);
49         if (err != CC3XX_ERR_EC_POINT_IS_INFINITY) {
50             FATAL_ERR(validate_succeeded = false);
51         }
52     }
53 
54     cc3xx_lowlevel_ec_free_point(&foo);
55     cc3xx_lowlevel_pka_free_reg(temp);
56     cc3xx_lowlevel_pka_free_reg(equation_right_side);
57     cc3xx_lowlevel_pka_free_reg(equation_left_side);
58 
59     return validate_succeeded;
60 }
61 
negate_point(cc3xx_ec_point_projective * p,cc3xx_ec_point_projective * res)62 static void negate_point(cc3xx_ec_point_projective *p,
63                          cc3xx_ec_point_projective *res)
64 {
65     if (p != res) {
66         cc3xx_lowlevel_pka_copy(p->x, res->x);
67         cc3xx_lowlevel_pka_copy(p->z, res->z);
68     }
69 
70     cc3xx_lowlevel_pka_mod_neg(p->y, res->y);
71 }
72 
cc3xx_lowlevel_ec_weierstrass_negate_point(cc3xx_ec_point_affine * p,cc3xx_ec_point_affine * res)73 void cc3xx_lowlevel_ec_weierstrass_negate_point(cc3xx_ec_point_affine *p,
74                                                 cc3xx_ec_point_affine *res)
75 {
76     /* No need to perform affine-to-projective conversion, since we can just
77      * negate the affine point */
78     if (p != res) {
79         cc3xx_lowlevel_pka_copy(p->x, res->x);
80     }
81 
82     cc3xx_lowlevel_pka_mod_neg(p->y, res->y);
83 }
84 
85 /* Using dbl-1998-cmo via https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo */
double_point(cc3xx_ec_curve_t * curve,cc3xx_ec_point_projective * p,cc3xx_ec_point_projective * res)86 static void double_point(cc3xx_ec_curve_t *curve, cc3xx_ec_point_projective *p,
87                          cc3xx_ec_point_projective *res)
88 {
89     cc3xx_pka_reg_id_t tmp_s = cc3xx_lowlevel_pka_allocate_reg();
90     cc3xx_pka_reg_id_t tmp_m = cc3xx_lowlevel_pka_allocate_reg();
91     cc3xx_pka_reg_id_t tmp = cc3xx_lowlevel_pka_allocate_reg();
92 
93     /* S = 4 * p->x * p->y^2 */
94     cc3xx_lowlevel_pka_mod_mul(p->y, p->y, tmp_s);
95     cc3xx_lowlevel_pka_mod_mul(tmp_s, p->x, tmp_s);
96     cc3xx_lowlevel_pka_mod_mul_si(tmp_s, 4, tmp_s);
97 
98     /* M = 3 * p->x^2 + a * p->z^4. Use tmp for a temporary variable. */
99     cc3xx_lowlevel_pka_mod_mul(p->x, p->x, tmp);
100     cc3xx_lowlevel_pka_mod_mul_si(tmp, 3, tmp);
101     cc3xx_lowlevel_pka_mod_mul(p->z, p->z, tmp_m);
102     cc3xx_lowlevel_pka_mod_mul(tmp_m, tmp_m, tmp_m);
103     cc3xx_lowlevel_pka_mod_mul(tmp_m, curve->param_a, tmp_m);
104     cc3xx_lowlevel_pka_mod_add(tmp_m, tmp, tmp_m);
105 
106     /* T = res->x = M^2 - 2 * S. Use tmp for a temporary variable. */
107     cc3xx_lowlevel_pka_mod_mul(tmp_m, tmp_m, res->x);
108     cc3xx_lowlevel_pka_mod_mul_si(tmp_s, 2, tmp);
109     cc3xx_lowlevel_pka_mod_sub(res->x, tmp, res->x);
110 
111     /* res->z = 2 * p->y * p->z This is done before res->y in
112      * case p == res, in which case setting res->y clobbers p->y which is needed
113      * in this step
114      */
115     cc3xx_lowlevel_pka_mod_mul(p->y, p->z, res->z);
116     cc3xx_lowlevel_pka_mod_mul_si(res->z, 2, res->z);
117 
118     /*
119      * res->y = M * (S - res->x) - 8 * p->y^4. Use tmp for a temporary variable.
120      */
121     cc3xx_lowlevel_pka_mod_mul(p->y, p->y, res->y);
122     cc3xx_lowlevel_pka_mod_mul(res->y, res->y, res->y);
123     cc3xx_lowlevel_pka_mod_mul_si(res->y, 8, res->y);
124 
125     cc3xx_lowlevel_pka_mod_sub(tmp_s, res->x, tmp);
126     cc3xx_lowlevel_pka_mod_mul(tmp_m, tmp, tmp);
127     cc3xx_lowlevel_pka_mod_sub(tmp, res->y, res->y);
128 
129     cc3xx_lowlevel_pka_free_reg(tmp);
130     cc3xx_lowlevel_pka_free_reg(tmp_m);
131     cc3xx_lowlevel_pka_free_reg(tmp_s);
132 }
133 
cc3xx_lowlevel_ec_weierstrass_double_point(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p,cc3xx_ec_point_affine * res)134 cc3xx_err_t cc3xx_lowlevel_ec_weierstrass_double_point(cc3xx_ec_curve_t *curve,
135                                                        cc3xx_ec_point_affine *p,
136                                                        cc3xx_ec_point_affine *res)
137 {
138     cc3xx_err_t err;
139 
140     cc3xx_ec_point_projective proj_p = cc3xx_lowlevel_ec_allocate_projective_point();
141     cc3xx_ec_point_projective proj_res = cc3xx_lowlevel_ec_allocate_projective_point();
142 
143     cc3xx_lowlevel_ec_affine_to_jacobian(curve, p, &proj_p);
144 
145     double_point(curve, &proj_p, &proj_res);
146 
147     err = cc3xx_lowlevel_ec_jacobian_to_affine(curve, &proj_res, res);
148 
149     cc3xx_lowlevel_ec_free_projective_point(&proj_res);
150     cc3xx_lowlevel_ec_free_projective_point(&proj_p);
151 
152     return err;
153 }
154 
155 /* Using add-1998-cmo via https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-1998-cmo
156  * It uses an older algorithm as it can be made more register-efficient.
157  */
add_points(cc3xx_ec_curve_t * curve,cc3xx_ec_point_projective * p,cc3xx_ec_point_projective * q,cc3xx_ec_point_projective * res)158 static void add_points(cc3xx_ec_curve_t *curve, cc3xx_ec_point_projective *p,
159                        cc3xx_ec_point_projective *q, cc3xx_ec_point_projective *res)
160 {
161     if ((p->x == q->x || cc3xx_lowlevel_pka_are_equal(p->x, q->x))
162      && (p->y == q->y || cc3xx_lowlevel_pka_are_equal(p->y, q->y))
163      && (p->z == q->z || cc3xx_lowlevel_pka_are_equal(p->z, q->z))) {
164         return double_point(curve, p, res);
165     }
166 
167     cc3xx_pka_reg_id_t tmp_u1 = cc3xx_lowlevel_pka_allocate_reg();
168     cc3xx_pka_reg_id_t tmp_u2 = cc3xx_lowlevel_pka_allocate_reg();
169     cc3xx_pka_reg_id_t tmp_s1 = cc3xx_lowlevel_pka_allocate_reg();
170     cc3xx_pka_reg_id_t tmp_s2 = cc3xx_lowlevel_pka_allocate_reg();
171 
172     /* This is just an alias, to make the maths match the reference */
173     cc3xx_pka_reg_id_t tmp_r;
174     cc3xx_pka_reg_id_t tmp_h;
175 
176     /* U1 = p->x * q->z^2 */
177     cc3xx_lowlevel_pka_mod_mul(q->z, q->z, tmp_u1);
178     cc3xx_lowlevel_pka_mod_mul(p->x, tmp_u1, tmp_u1);
179     /* U2 = q->x * p->z^2 */
180     cc3xx_lowlevel_pka_mod_mul(p->z, p->z, tmp_u2);
181     cc3xx_lowlevel_pka_mod_mul(q->x, tmp_u2, tmp_u2);
182 
183     /* S1 = p->y * q->z^3 */
184     cc3xx_lowlevel_pka_mod_mul(q->z, q->z, tmp_s1);
185     cc3xx_lowlevel_pka_mod_mul(tmp_s1, q->z, tmp_s1);
186     cc3xx_lowlevel_pka_mod_mul(tmp_s1, p->y, tmp_s1);
187     /* S2 = q->y * p->z^3 */
188     cc3xx_lowlevel_pka_mod_mul(p->z, p->z, tmp_s2);
189     cc3xx_lowlevel_pka_mod_mul(tmp_s2, p->z, tmp_s2);
190     cc3xx_lowlevel_pka_mod_mul(tmp_s2, q->y, tmp_s2);
191 
192     /* tmp_u2 is never used after this point, so we can use it to store the h
193      * intermediate value
194      */
195     tmp_h = tmp_u2;
196 
197     /* H = U2 - U1 */
198     cc3xx_lowlevel_pka_mod_sub(tmp_u2, tmp_u1, tmp_h);
199 
200     /* tmp_s2 is never used after this point, so we can use it to store the r
201      * intermediate value
202      */
203     tmp_r = tmp_s2;
204 
205     /* R = S2 - S1 */
206     cc3xx_lowlevel_pka_mod_sub(tmp_s2, tmp_s1, tmp_r);
207 
208     /* res->x = R^2 - H^3 - 2 * U1 * H^2. Uses res->y as scratch space */
209     cc3xx_lowlevel_pka_shift_left_fill_0_ui(tmp_u1, 1, res->y);
210     cc3xx_lowlevel_pka_reduce(res->y);
211     cc3xx_lowlevel_pka_mod_mul(res->y, tmp_h, res->y);
212     cc3xx_lowlevel_pka_mod_mul(res->y, tmp_h, res->y);
213     cc3xx_lowlevel_pka_mod_mul(tmp_r, tmp_r, res->x);
214     cc3xx_lowlevel_pka_mod_sub(res->x, res->y, res->x);
215     cc3xx_lowlevel_pka_mod_mul(tmp_h, tmp_h, res->y);
216     cc3xx_lowlevel_pka_mod_mul(res->y, tmp_h, res->y);
217     cc3xx_lowlevel_pka_mod_sub(res->x, res->y, res->x);
218 
219     /* res->y = R * (U1 * H^2 - res->x) - S1 * H^3. Uses S1 as scratch space */
220     cc3xx_lowlevel_pka_mod_mul(tmp_h, tmp_h, res->y);
221     cc3xx_lowlevel_pka_mod_mul(res->y, tmp_u1, res->y);
222     cc3xx_lowlevel_pka_mod_sub(res->y, res->x, res->y);
223     cc3xx_lowlevel_pka_mod_mul(res->y, tmp_r, res->y);
224     /* res->z already contains H^3 */
225     cc3xx_lowlevel_pka_mod_mul(tmp_s1, tmp_h, tmp_s1);
226     cc3xx_lowlevel_pka_mod_mul(tmp_s1, tmp_h, tmp_s1);
227     cc3xx_lowlevel_pka_mod_mul(tmp_s1, tmp_h, tmp_s1);
228     cc3xx_lowlevel_pka_mod_sub(res->y, tmp_s1, res->y);
229 
230     /* res->z = p->z * q->z * H */
231     cc3xx_lowlevel_pka_mod_mul(p->z, q->z, res->z);
232     cc3xx_lowlevel_pka_mod_mul(res->z, tmp_h, res->z);
233 
234     cc3xx_lowlevel_pka_free_reg(tmp_s2);
235     cc3xx_lowlevel_pka_free_reg(tmp_s1);
236     cc3xx_lowlevel_pka_free_reg(tmp_u2);
237     cc3xx_lowlevel_pka_free_reg(tmp_u1);
238 }
239 
cc3xx_lowlevel_ec_weierstrass_add_points(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p,cc3xx_ec_point_affine * q,cc3xx_ec_point_affine * res)240 cc3xx_err_t cc3xx_lowlevel_ec_weierstrass_add_points(cc3xx_ec_curve_t *curve,
241                                                      cc3xx_ec_point_affine *p,
242                                                      cc3xx_ec_point_affine *q,
243                                                      cc3xx_ec_point_affine *res)
244 {
245     cc3xx_err_t err;
246 
247     cc3xx_ec_point_projective proj_p = cc3xx_lowlevel_ec_allocate_projective_point();
248     cc3xx_ec_point_projective proj_q = cc3xx_lowlevel_ec_allocate_projective_point();
249     cc3xx_ec_point_projective proj_res = cc3xx_lowlevel_ec_allocate_projective_point();
250 
251     cc3xx_lowlevel_ec_affine_to_jacobian(curve, p, &proj_p);
252     cc3xx_lowlevel_ec_affine_to_jacobian(curve, q, &proj_q);
253 
254     add_points(curve, &proj_p, &proj_q, &proj_res);
255 
256     err = cc3xx_lowlevel_ec_jacobian_to_affine(curve, &proj_res, res);
257 
258     cc3xx_lowlevel_ec_free_projective_point(&proj_res);
259     cc3xx_lowlevel_ec_free_projective_point(&proj_q);
260     cc3xx_lowlevel_ec_free_projective_point(&proj_p);
261 
262     return err;
263 }
264 
multipy_point_by_scalar_side_channel_protected(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p,cc3xx_pka_reg_id_t scalar,cc3xx_ec_point_affine * res)265 static cc3xx_err_t multipy_point_by_scalar_side_channel_protected(
266                                              cc3xx_ec_curve_t *curve,
267                                              cc3xx_ec_point_affine *p,
268                                              cc3xx_pka_reg_id_t scalar,
269                                              cc3xx_ec_point_affine *res)
270 {
271     int32_t idx;
272     uint8_t bit_pair;
273     int32_t carry;
274     uint32_t table_select;
275     cc3xx_err_t err = CC3XX_ERR_SUCCESS;
276 
277     cc3xx_ec_point_projective accumulator = cc3xx_lowlevel_ec_allocate_projective_point();
278     cc3xx_ec_point_projective final_carry_accumulator;
279 
280     cc3xx_ec_point_projective proj_p = cc3xx_lowlevel_ec_allocate_projective_point();
281     cc3xx_ec_point_projective proj_neg_p = cc3xx_lowlevel_ec_allocate_projective_point();
282     cc3xx_ec_point_projective proj_2p = cc3xx_lowlevel_ec_allocate_projective_point();
283     cc3xx_ec_point_projective proj_neg_2p = cc3xx_lowlevel_ec_allocate_projective_point();
284     cc3xx_ec_point_projective proj_4p = cc3xx_lowlevel_ec_allocate_projective_point();
285     cc3xx_ec_point_projective proj_neg_4p = cc3xx_lowlevel_ec_allocate_projective_point();
286 
287     /* The index in the point add table plus the index in the carry table is
288      * equal to p * index. For example, at index 1, we take proj_neg_2p with a
289      * -1 carry to make -3 * p. This allows all point multiples from -4 * p to
290      *  3 * p to be constructed only from the even multiples, and crucially
291      *  allows the inner loop to avoid any branching. This would be possible
292      *  with a smaller table as well, but would be much less efficient. We can't
293      *  precalculate a larger even-multiple table (or a full even/odd multiple
294      *  table) because we'd run out of physical PKA registers, which would cause
295      *  a _huge_ performance hit with a register flush/remap in the inner loop.
296      */
297     cc3xx_ec_point_projective point_add_table[8] = {
298         proj_neg_4p, proj_neg_2p, proj_neg_2p, proj_neg_p,
299         proj_p,      proj_p,      proj_2p,     proj_4p,
300     };
301     int32_t carry_table[8] = { 0, -1, 0, 0, -1, 0, 0, -1, };
302 
303     /* This must be done before the unmap, so that p isn't mapped for the main
304      * part of this function.
305      */
306     cc3xx_lowlevel_ec_affine_to_jacobian_with_random_z(curve, p, &proj_p);
307     cc3xx_lowlevel_pka_unmap_physical_registers();
308 
309     /* calculate the necessary multiples */
310     negate_point(&proj_p, &proj_neg_p);
311     double_point(curve, &proj_p, &proj_2p);
312     double_point(curve, &proj_p, &proj_2p);
313     double_point(curve, &proj_p, &proj_2p);
314     double_point(curve, &proj_p, &proj_2p);
315     double_point(curve, &proj_p, &proj_2p);
316     double_point(curve, &proj_p, &proj_2p);
317     double_point(curve, &proj_p, &proj_2p);
318     negate_point(&proj_2p, &proj_neg_2p);
319     double_point(curve, &proj_2p, &proj_4p);
320     negate_point(&proj_4p, &proj_neg_4p);
321 
322     /* This needs to be two-aligned for the two-sized window to work. The upper
323      * bits are zero, so this is fine
324      */
325     idx = cc3xx_lowlevel_pka_get_bit_size(scalar);
326     if (idx & 1) {
327         idx += 1;
328     }
329 
330     idx -= 2;
331     bit_pair = cc3xx_lowlevel_pka_test_bits_ui(scalar, idx, 2);
332     /* This should never happen */
333     assert(bit_pair != 0);
334     idx -= 2;
335 
336     table_select = bit_pair + 4;
337     cc3xx_lowlevel_ec_copy_projective_point(&point_add_table[table_select], &accumulator);
338     carry = carry_table[table_select];
339 
340     for (; idx >= 0; idx -= 2) {
341         /* Multiple accumulator by 4, performing two doubles */
342         double_point(curve, &accumulator, &accumulator);
343         double_point(curve, &accumulator, &accumulator);
344 
345         /* Select which multiple will be added based on the value of the
346          * bit-pair and the carry. This also determines the new carry value.
347          */
348         bit_pair = cc3xx_lowlevel_pka_test_bits_ui(scalar, idx, 2);
349         table_select = (carry * 4) + bit_pair + 4;
350 
351         add_points(curve, &accumulator, &point_add_table[table_select], &accumulator);
352         carry = carry_table[table_select];
353 
354         if (cc3xx_lowlevel_ec_projective_point_is_infinity(&accumulator)) {
355             FATAL_ERR(err |= CC3XX_ERR_EC_POINT_IS_INFINITY);
356         }
357     }
358 
359 
360     /* Free some of the points that aren't used from now on, to get physical
361      * registers back to map the final_carry_accumulator.
362      */
363     cc3xx_lowlevel_ec_free_projective_point(&proj_neg_4p);
364     cc3xx_lowlevel_ec_free_projective_point(&proj_4p);
365     cc3xx_lowlevel_ec_free_projective_point(&proj_neg_2p);
366     cc3xx_lowlevel_ec_free_projective_point(&proj_2p);
367 
368     cc3xx_lowlevel_pka_unmap_physical_registers();
369 
370     final_carry_accumulator = cc3xx_lowlevel_ec_allocate_projective_point();
371 
372     add_points(curve, &accumulator, &proj_neg_p, &final_carry_accumulator);
373 
374     if (carry == -1) {
375         err |= cc3xx_lowlevel_ec_jacobian_to_affine(curve, &final_carry_accumulator,
376                                                     res);
377     } else {
378         err |= cc3xx_lowlevel_ec_jacobian_to_affine(curve, &accumulator, res);
379     }
380 
381     if (err != CC3XX_ERR_SUCCESS) {
382         cc3xx_lowlevel_pka_clear(res->x);
383         cc3xx_lowlevel_pka_clear(res->y);
384     }
385 
386     cc3xx_lowlevel_ec_free_projective_point(&final_carry_accumulator);
387     cc3xx_lowlevel_ec_free_projective_point(&proj_neg_p);
388     cc3xx_lowlevel_ec_free_projective_point(&proj_p);
389     cc3xx_lowlevel_ec_free_projective_point(&accumulator);
390 
391     return err;
392 }
393 
shamir_multiply_points_by_scalars_and_add(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p1,cc3xx_pka_reg_id_t scalar1,cc3xx_ec_point_affine * p2,cc3xx_pka_reg_id_t scalar2,cc3xx_ec_point_affine * res)394 static cc3xx_err_t shamir_multiply_points_by_scalars_and_add(
395                                              cc3xx_ec_curve_t *curve,
396                                              cc3xx_ec_point_affine *p1,
397                                              cc3xx_pka_reg_id_t    scalar1,
398                                              cc3xx_ec_point_affine *p2,
399                                              cc3xx_pka_reg_id_t    scalar2,
400                                              cc3xx_ec_point_affine *res)
401 {
402     int32_t idx;
403     uint32_t bitsize1;
404     uint32_t bitsize2;
405     uint32_t bit1;
406     uint32_t bit2;
407     uint32_t bit_pair;
408     cc3xx_err_t err = CC3XX_ERR_SUCCESS;
409     cc3xx_ec_point_projective proj_p1 = cc3xx_lowlevel_ec_allocate_projective_point();
410     cc3xx_ec_point_projective proj_p2 = cc3xx_lowlevel_ec_allocate_projective_point();
411     cc3xx_ec_point_projective p1_plus_p2 = cc3xx_lowlevel_ec_allocate_projective_point();
412     cc3xx_ec_point_projective accumulator = cc3xx_lowlevel_ec_allocate_projective_point();
413 
414     assert(cc3xx_lowlevel_pka_greater_than_si(scalar1, 0)
415            || cc3xx_lowlevel_pka_greater_than_si(scalar2, 0));
416 
417     bitsize1 = cc3xx_lowlevel_pka_get_bit_size(scalar1);
418     bitsize2 = cc3xx_lowlevel_pka_get_bit_size(scalar2);
419 
420     cc3xx_lowlevel_pka_unmap_physical_registers();
421 
422     cc3xx_lowlevel_ec_affine_to_jacobian(curve, p1, &proj_p1);
423     cc3xx_lowlevel_ec_affine_to_jacobian(curve, p2, &proj_p2);
424 
425     add_points(curve, &proj_p1, &proj_p2, &p1_plus_p2);
426 
427     if (bitsize1 > bitsize2) {
428         cc3xx_lowlevel_ec_copy_projective_point(&proj_p1, &accumulator);
429         idx = bitsize1;
430     } else if (bitsize2 > bitsize1) {
431         cc3xx_lowlevel_ec_copy_projective_point(&proj_p2, &accumulator);
432         idx = bitsize2;
433     } else {
434         cc3xx_lowlevel_ec_copy_projective_point(&p1_plus_p2, &accumulator);
435         idx = bitsize2;
436     }
437 
438     idx -= 2;
439 
440     for (; idx >= 0; idx--) {
441         double_point(curve, &accumulator, &accumulator);
442 
443         bit1 = cc3xx_lowlevel_pka_test_bits_ui(scalar1, idx, 1);
444         bit2 = cc3xx_lowlevel_pka_test_bits_ui(scalar2, idx, 1);
445         bit_pair = (bit1 << 1) + bit2;
446 
447         switch (bit_pair) {
448         case 1:
449             add_points(curve, &accumulator, &proj_p2, &accumulator);
450             break;
451         case 2:
452             add_points(curve, &accumulator, &proj_p1, &accumulator);
453             break;
454         case 3:
455             add_points(curve, &accumulator, &p1_plus_p2, &accumulator);
456             break;
457         }
458 
459         if (cc3xx_lowlevel_ec_projective_point_is_infinity(&accumulator)) {
460             FATAL_ERR(err |= CC3XX_ERR_EC_POINT_IS_INFINITY);
461         }
462     }
463 
464     err |= cc3xx_lowlevel_ec_jacobian_to_affine(curve, &accumulator, res);
465 
466     cc3xx_lowlevel_ec_free_projective_point(&accumulator);
467     cc3xx_lowlevel_ec_free_projective_point(&p1_plus_p2);
468     cc3xx_lowlevel_ec_free_projective_point(&proj_p2);
469     cc3xx_lowlevel_ec_free_projective_point(&proj_p1);
470 
471     cc3xx_lowlevel_pka_unmap_physical_registers();
472 
473     return err;
474 }
475 
cc3xx_lowlevel_ec_weierstrass_multipy_point_by_scalar(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p,cc3xx_pka_reg_id_t scalar,cc3xx_ec_point_affine * res)476 cc3xx_err_t cc3xx_lowlevel_ec_weierstrass_multipy_point_by_scalar(
477                                              cc3xx_ec_curve_t *curve,
478                                              cc3xx_ec_point_affine *p,
479                                              cc3xx_pka_reg_id_t scalar,
480                                              cc3xx_ec_point_affine *res)
481 {
482     /* If we only ever handle non-secret data, we can save some code size by
483      * using the Shamir trick exponentiation with a zero as the second scalar
484      */
485 #if defined(CC3XX_CONFIG_EC_SHAMIR_TRICK_ENABLE) && defined(CC3XX_CONFIG_ECDSA_VERIFY_ENABLE) \
486     && !defined(CC3XX_CONFIG_ECDSA_SIGN_ENABLE) && !defined(CC3XX_CONFIG_ECDSA_KEYGEN_ENABLE) \
487     && !defined(CC3XX_CONFIG_ECDH_ENABLE) /* If ECDH is enabled we treat secret data in the multiplication */
488     cc3xx_err_t err = CC3XX_ERR_SUCCESS;
489     cc3xx_pka_reg_id_t zero_reg = cc3xx_lowlevel_pka_allocate_reg();
490 
491     cc3xx_lowlevel_pka_clear(zero_reg);
492     err = shamir_multiply_points_by_scalars_and_add(curve, p, scalar,
493                                                     p, zero_reg, res);
494 
495     cc3xx_lowlevel_pka_free_reg(zero_reg);
496     return err;
497 #else
498     return multipy_point_by_scalar_side_channel_protected(curve, p, scalar, res);
499 #endif
500 }
501 
cc3xx_lowlevel_ec_weierstrass_shamir_multiply_points_by_scalars_and_add(cc3xx_ec_curve_t * curve,cc3xx_ec_point_affine * p1,cc3xx_pka_reg_id_t scalar1,cc3xx_ec_point_affine * p2,cc3xx_pka_reg_id_t scalar2,cc3xx_ec_point_affine * res)502 cc3xx_err_t cc3xx_lowlevel_ec_weierstrass_shamir_multiply_points_by_scalars_and_add(
503                                              cc3xx_ec_curve_t *curve,
504                                              cc3xx_ec_point_affine *p1,
505                                              cc3xx_pka_reg_id_t    scalar1,
506                                              cc3xx_ec_point_affine *p2,
507                                              cc3xx_pka_reg_id_t    scalar2,
508                                              cc3xx_ec_point_affine *res)
509 {
510 #ifdef CC3XX_CONFIG_EC_SHAMIR_TRICK_ENABLE
511     return shamir_multiply_points_by_scalars_and_add(curve,
512                                                      p1, scalar1,
513                                                      p2, scalar2, res);
514 #else
515     cc3xx_err_t err = CC3XX_ERR_SUCCESS;
516     cc3xx_ec_point_affine temp_point = cc3xx_lowlevel_ec_allocate_point();
517 
518     err |= multipy_point_by_scalar_side_channel_protected(curve, p1, scalar1,
519                                                           &temp_point);
520     err |= multipy_point_by_scalar_side_channel_protected(curve, p2, scalar2,
521                                                           res);
522     err |= cc3xx_lowlevel_ec_add_points(curve, &temp_point, res, res);
523 
524     cc3xx_lowlevel_ec_free_point(&temp_point);
525 
526     return err;
527 #endif /* CC3XX_CONFIG_EC_SHAMIR_TRICK_ENABLE */
528 }
529