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