blob: b2203ba9a4ca4d54b9aa043cadb1f932abc3bc9e [file] [log] [blame]
gabor-mezei-armd1125342021-07-12 16:31:22 +02001/**
2 * Constant-time functions
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#include "common.h"
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020021#include "constant_time.h"
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +020022#include "mbedtls/error.h"
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020023
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +020024#if defined(MBEDTLS_BIGNUM_C)
25#include "mbedtls/bignum.h"
26#endif
27
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +020028#if defined(MBEDTLS_SSL_TLS_C)
29#include "ssl_misc.h"
30#endif
31
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +020032
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020033/* constant-time buffer comparison */
34int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
35{
36 size_t i;
37 volatile const unsigned char *A = (volatile const unsigned char *) a;
38 volatile const unsigned char *B = (volatile const unsigned char *) b;
39 volatile unsigned char diff = 0;
40
41 for( i = 0; i < n; i++ )
42 {
43 /* Read volatile data in order before computing diff.
44 * This avoids IAR compiler warning:
45 * 'the order of volatile accesses is undefined ..' */
46 unsigned char x = A[i], y = B[i];
47 diff |= x ^ y;
48 }
49
50 return( diff );
51}
52
53/* Compare the contents of two buffers in constant time.
54 * Returns 0 if the contents are bitwise identical, otherwise returns
55 * a non-zero value.
56 * This is currently only used by GCM and ChaCha20+Poly1305.
57 */
58int mbedtls_constant_time_memcmp( const void *v1, const void *v2,
59 size_t len )
60{
61 const unsigned char *p1 = (const unsigned char*) v1;
62 const unsigned char *p2 = (const unsigned char*) v2;
63 size_t i;
64 unsigned char diff;
65
66 for( diff = 0, i = 0; i < len; i++ )
67 diff |= p1[i] ^ p2[i];
68
69 return( (int)diff );
70}
71
72/* constant-time buffer comparison */
73unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
74{
75 size_t i;
76 volatile const unsigned char *A = (volatile const unsigned char *) a;
77 volatile const unsigned char *B = (volatile const unsigned char *) b;
78 volatile unsigned char diff = 0;
79
80 for( i = 0; i < n; i++ )
81 {
82 /* Read volatile data in order before computing diff.
83 * This avoids IAR compiler warning:
84 * 'the order of volatile accesses is undefined ..' */
85 unsigned char x = A[i], y = B[i];
86 diff |= x ^ y;
87 }
88
89 return( diff );
90}
91
92/* constant-time buffer comparison */
93int mbedtls_safer_memcmp( const void *a, const void *b, size_t n )
94{
95 size_t i;
96 const unsigned char *A = (const unsigned char *) a;
97 const unsigned char *B = (const unsigned char *) b;
98 unsigned char diff = 0;
99
100 for( i = 0; i < n; i++ )
101 diff |= A[i] ^ B[i];
102
103 return( diff );
104}
gabor-mezei-arm340948e2021-09-27 11:40:03 +0200105
106/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches.
107 *
108 * \param value The value to analyze.
109 * \return Zero if \p value is zero, otherwise all-bits-one.
110 */
111unsigned mbedtls_cf_uint_mask( unsigned value )
112{
113 /* MSVC has a warning about unary minus on unsigned, but this is
114 * well-defined and precisely what we want to do here */
115#if defined(_MSC_VER)
116#pragma warning( push )
117#pragma warning( disable : 4146 )
118#endif
119 return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) );
120#if defined(_MSC_VER)
121#pragma warning( pop )
122#endif
123}
gabor-mezei-arm3733bf82021-09-27 11:49:42 +0200124
125/*
126 * Turn a bit into a mask:
127 * - if bit == 1, return the all-bits 1 mask, aka (size_t) -1
128 * - if bit == 0, return the all-bits 0 mask, aka 0
129 *
130 * This function can be used to write constant-time code by replacing branches
131 * with bit operations using masks.
132 *
133 * This function is implemented without using comparison operators, as those
134 * might be translated to branches by some compilers on some platforms.
135 */
136size_t mbedtls_cf_size_mask( size_t bit )
137{
138 /* MSVC has a warning about unary minus on unsigned integer types,
139 * but this is well-defined and precisely what we want to do here. */
140#if defined(_MSC_VER)
141#pragma warning( push )
142#pragma warning( disable : 4146 )
143#endif
144 return -bit;
145#if defined(_MSC_VER)
146#pragma warning( pop )
147#endif
148}
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200149
150/*
151 * Constant-flow mask generation for "less than" comparison:
152 * - if x < y, return all bits 1, that is (size_t) -1
153 * - otherwise, return all bits 0, that is 0
154 *
155 * This function can be used to write constant-time code by replacing branches
156 * with bit operations using masks.
157 *
158 * This function is implemented without using comparison operators, as those
159 * might be translated to branches by some compilers on some platforms.
160 */
161size_t mbedtls_cf_size_mask_lt( size_t x, size_t y )
162{
163 /* This has the most significant bit set if and only if x < y */
164 const size_t sub = x - y;
165
166 /* sub1 = (x < y) ? 1 : 0 */
167 const size_t sub1 = sub >> ( sizeof( sub ) * 8 - 1 );
168
169 /* mask = (x < y) ? 0xff... : 0x00... */
170 const size_t mask = mbedtls_cf_size_mask( sub1 );
171
172 return( mask );
173}
gabor-mezei-arm16fc57b2021-09-27 11:58:31 +0200174
175/*
176 * Constant-flow mask generation for "greater or equal" comparison:
177 * - if x >= y, return all bits 1, that is (size_t) -1
178 * - otherwise, return all bits 0, that is 0
179 *
180 * This function can be used to write constant-time code by replacing branches
181 * with bit operations using masks.
182 *
183 * This function is implemented without using comparison operators, as those
184 * might be translated to branches by some compilers on some platforms.
185 */
186size_t mbedtls_cf_size_mask_ge( size_t x, size_t y )
187{
188 return( ~mbedtls_cf_size_mask_lt( x, y ) );
189}
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200190
191/*
192 * Constant-flow boolean "equal" comparison:
193 * return x == y
194 *
195 * This function can be used to write constant-time code by replacing branches
196 * with bit operations - it can be used in conjunction with
197 * mbedtls_ssl_cf_mask_from_bit().
198 *
199 * This function is implemented without using comparison operators, as those
200 * might be translated to branches by some compilers on some platforms.
201 */
202size_t mbedtls_cf_size_bool_eq( size_t x, size_t y )
203{
204 /* diff = 0 if x == y, non-zero otherwise */
205 const size_t diff = x ^ y;
206
207 /* MSVC has a warning about unary minus on unsigned integer types,
208 * but this is well-defined and precisely what we want to do here. */
209#if defined(_MSC_VER)
210#pragma warning( push )
211#pragma warning( disable : 4146 )
212#endif
213
214 /* diff_msb's most significant bit is equal to x != y */
215 const size_t diff_msb = ( diff | (size_t) -diff );
216
217#if defined(_MSC_VER)
218#pragma warning( pop )
219#endif
220
221 /* diff1 = (x != y) ? 1 : 0 */
222 const size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 );
223
224 return( 1 ^ diff1 );
225}
gabor-mezei-arm5a854422021-09-27 12:25:07 +0200226
227/** Check whether a size is out of bounds, without branches.
228 *
229 * This is equivalent to `size > max`, but is likely to be compiled to
230 * to code using bitwise operation rather than a branch.
231 *
232 * \param size Size to check.
233 * \param max Maximum desired value for \p size.
234 * \return \c 0 if `size <= max`.
235 * \return \c 1 if `size > max`.
236 */
237unsigned mbedtls_cf_size_gt( size_t size, size_t max )
238{
239 /* Return the sign bit (1 for negative) of (max - size). */
240 return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) );
241}
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200242
243#if defined(MBEDTLS_BIGNUM_C)
244
245/** Decide if an integer is less than the other, without branches.
246 *
247 * \param x First integer.
248 * \param y Second integer.
249 *
250 * \return 1 if \p x is less than \p y, 0 otherwise
251 */
252unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x,
253 const mbedtls_mpi_uint y )
254{
255 mbedtls_mpi_uint ret;
256 mbedtls_mpi_uint cond;
257
258 /*
259 * Check if the most significant bits (MSB) of the operands are different.
260 */
261 cond = ( x ^ y );
262 /*
263 * If the MSB are the same then the difference x-y will be negative (and
264 * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
265 */
266 ret = ( x - y ) & ~cond;
267 /*
268 * If the MSB are different, then the operand with the MSB of 1 is the
269 * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
270 * the MSB of y is 0.)
271 */
272 ret |= y & cond;
273
274
275 ret = ret >> ( sizeof( mbedtls_mpi_uint ) * 8 - 1 );
276
277 return (unsigned) ret;
278}
279
280#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-armb2dbf2c2021-09-27 12:59:30 +0200281
282/** Choose between two integer values, without branches.
283 *
284 * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled
285 * to code using bitwise operation rather than a branch.
286 *
287 * \param cond Condition to test.
288 * \param if1 Value to use if \p cond is nonzero.
289 * \param if0 Value to use if \p cond is zero.
290 * \return \c if1 if \p cond is nonzero, otherwise \c if0.
291 */
292unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 )
293{
294 unsigned mask = mbedtls_cf_uint_mask( cond );
295 return( ( mask & if1 ) | (~mask & if0 ) );
296}
gabor-mezei-armd3230d52021-09-27 13:03:57 +0200297
298/**
299 * Select between two sign values in constant-time.
300 *
301 * This is functionally equivalent to second ? a : b but uses only bit
302 * operations in order to avoid branches.
303 *
304 * \param[in] a The first sign; must be either +1 or -1.
305 * \param[in] b The second sign; must be either +1 or -1.
306 * \param[in] second Must be either 1 (return b) or 0 (return a).
307 *
308 * \return The selected sign value.
309 */
310int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second )
311{
312 /* In order to avoid questions about what we can reasonnably assume about
313 * the representations of signed integers, move everything to unsigned
314 * by taking advantage of the fact that a and b are either +1 or -1. */
315 unsigned ua = a + 1;
316 unsigned ub = b + 1;
317
318 /* second was 0 or 1, mask is 0 or 2 as are ua and ub */
319 const unsigned mask = second << 1;
320
321 /* select ua or ub */
322 unsigned ur = ( ua & ~mask ) | ( ub & mask );
323
324 /* ur is now 0 or 2, convert back to -1 or +1 */
325 return( (int) ur - 1 );
326}
gabor-mezei-armbe8d98b2021-09-27 13:17:15 +0200327
328#if defined(MBEDTLS_BIGNUM_C)
329
330/*
331 * Conditionally assign dest = src, without leaking information
332 * about whether the assignment was made or not.
333 * dest and src must be arrays of limbs of size n.
334 * assign must be 0 or 1.
335 */
336void mbedtls_cf_mpi_uint_cond_assign( size_t n,
337 mbedtls_mpi_uint *dest,
338 const mbedtls_mpi_uint *src,
339 unsigned char assign )
340{
341 size_t i;
342
343 /* MSVC has a warning about unary minus on unsigned integer types,
344 * but this is well-defined and precisely what we want to do here. */
345#if defined(_MSC_VER)
346#pragma warning( push )
347#pragma warning( disable : 4146 )
348#endif
349
350 /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
351 const mbedtls_mpi_uint mask = -assign;
352
353#if defined(_MSC_VER)
354#pragma warning( pop )
355#endif
356
357 for( i = 0; i < n; i++ )
358 dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask );
359}
360
361#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200362
363/** Shift some data towards the left inside a buffer without leaking
364 * the length of the data through side channels.
365 *
366 * `mbedtls_cf_mem_move_to_left(start, total, offset)` is functionally
367 * equivalent to
368 * ```
369 * memmove(start, start + offset, total - offset);
370 * memset(start + offset, 0, total - offset);
371 * ```
372 * but it strives to use a memory access pattern (and thus total timing)
373 * that does not depend on \p offset. This timing independence comes at
374 * the expense of performance.
375 *
376 * \param start Pointer to the start of the buffer.
377 * \param total Total size of the buffer.
378 * \param offset Offset from which to copy \p total - \p offset bytes.
379 */
380void mbedtls_cf_mem_move_to_left( void *start,
381 size_t total,
382 size_t offset )
383{
384 volatile unsigned char *buf = start;
385 size_t i, n;
386 if( total == 0 )
387 return;
388 for( i = 0; i < total; i++ )
389 {
390 unsigned no_op = mbedtls_cf_size_gt( total - offset, i );
391 /* The first `total - offset` passes are a no-op. The last
392 * `offset` passes shift the data one byte to the left and
393 * zero out the last byte. */
394 for( n = 0; n < total - 1; n++ )
395 {
396 unsigned char current = buf[n];
397 unsigned char next = buf[n+1];
398 buf[n] = mbedtls_cf_uint_if( no_op, current, next );
399 }
400 buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 );
401 }
402}
gabor-mezei-armdee0fd32021-09-27 13:34:25 +0200403
404/*
405 * Constant-flow conditional memcpy:
406 * - if c1 == c2, equivalent to memcpy(dst, src, len),
407 * - otherwise, a no-op,
408 * but with execution flow independent of the values of c1 and c2.
409 *
410 * This function is implemented without using comparison operators, as those
411 * might be translated to branches by some compilers on some platforms.
412 */
413void mbedtls_cf_memcpy_if_eq( unsigned char *dst,
414 const unsigned char *src,
415 size_t len,
416 size_t c1, size_t c2 )
417{
418 /* mask = c1 == c2 ? 0xff : 0x00 */
419 const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 );
420 const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal );
421
422 /* dst[i] = c1 == c2 ? src[i] : dst[i] */
423 for( size_t i = 0; i < len; i++ )
424 dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask );
425}
gabor-mezei-arm0e7f71e2021-09-27 13:57:45 +0200426
427/*
428 * Constant-flow memcpy from variable position in buffer.
429 * - functionally equivalent to memcpy(dst, src + offset_secret, len)
430 * - but with execution flow independent from the value of offset_secret.
431 */
432void mbedtls_cf_memcpy_offset(
433 unsigned char *dst,
434 const unsigned char *src_base,
435 size_t offset_secret,
436 size_t offset_min, size_t offset_max,
437 size_t len )
438{
439 size_t offset;
440
441 for( offset = offset_min; offset <= offset_max; offset++ )
442 {
443 mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len,
444 offset, offset_secret );
445 }
446}
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +0200447
448#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
449
450/*
451 * Compute HMAC of variable-length data with constant flow.
452 *
453 * Only works with MD-5, SHA-1, SHA-256 and SHA-384.
454 * (Otherwise, computation of block_size needs to be adapted.)
455 */
456int mbedtls_cf_hmac(
457 mbedtls_md_context_t *ctx,
458 const unsigned char *add_data, size_t add_data_len,
459 const unsigned char *data, size_t data_len_secret,
460 size_t min_data_len, size_t max_data_len,
461 unsigned char *output )
462{
463 /*
464 * This function breaks the HMAC abstraction and uses the md_clone()
465 * extension to the MD API in order to get constant-flow behaviour.
466 *
467 * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
468 * concatenation, and okey/ikey are the XOR of the key with some fixed bit
469 * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
470 *
471 * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
472 * minlen, then cloning the context, and for each byte up to maxlen
473 * finishing up the hash computation, keeping only the correct result.
474 *
475 * Then we only need to compute HASH(okey + inner_hash) and we're done.
476 */
477 const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info );
478 /* TLS 1.2 only supports SHA-384, SHA-256, SHA-1, MD-5,
479 * all of which have the same block size except SHA-384. */
480 const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
481 const unsigned char * const ikey = ctx->hmac_ctx;
482 const unsigned char * const okey = ikey + block_size;
483 const size_t hash_size = mbedtls_md_get_size( ctx->md_info );
484
485 unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
486 mbedtls_md_context_t aux;
487 size_t offset;
488 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
489
490 mbedtls_md_init( &aux );
491
492#define MD_CHK( func_call ) \
493 do { \
494 ret = (func_call); \
495 if( ret != 0 ) \
496 goto cleanup; \
497 } while( 0 )
498
499 MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
500
501 /* After hmac_start() of hmac_reset(), ikey has already been hashed,
502 * so we can start directly with the message */
503 MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) );
504 MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) );
505
506 /* For each possible length, compute the hash up to that point */
507 for( offset = min_data_len; offset <= max_data_len; offset++ )
508 {
509 MD_CHK( mbedtls_md_clone( &aux, ctx ) );
510 MD_CHK( mbedtls_md_finish( &aux, aux_out ) );
511 /* Keep only the correct inner_hash in the output buffer */
512 mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size,
513 offset, data_len_secret );
514
515 if( offset < max_data_len )
516 MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) );
517 }
518
519 /* The context needs to finish() before it starts() again */
520 MD_CHK( mbedtls_md_finish( ctx, aux_out ) );
521
522 /* Now compute HASH(okey + inner_hash) */
523 MD_CHK( mbedtls_md_starts( ctx ) );
524 MD_CHK( mbedtls_md_update( ctx, okey, block_size ) );
525 MD_CHK( mbedtls_md_update( ctx, output, hash_size ) );
526 MD_CHK( mbedtls_md_finish( ctx, output ) );
527
528 /* Done, get ready for next time */
529 MD_CHK( mbedtls_md_hmac_reset( ctx ) );
530
531#undef MD_CHK
532
533cleanup:
534 mbedtls_md_free( &aux );
535 return( ret );
536}
537
538#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200539
540#if defined(MBEDTLS_BIGNUM_C)
541
542#define MPI_VALIDATE_RET( cond ) \
543 MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA )
544
545/*
546 * Conditionally assign X = Y, without leaking information
547 * about whether the assignment was made or not.
548 * (Leaking information about the respective sizes of X and Y is ok however.)
549 */
550int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign )
551{
552 int ret = 0;
553 size_t i;
554 mbedtls_mpi_uint limb_mask;
555 MPI_VALIDATE_RET( X != NULL );
556 MPI_VALIDATE_RET( Y != NULL );
557
558 /* MSVC has a warning about unary minus on unsigned integer types,
559 * but this is well-defined and precisely what we want to do here. */
560#if defined(_MSC_VER)
561#pragma warning( push )
562#pragma warning( disable : 4146 )
563#endif
564
565 /* make sure assign is 0 or 1 in a time-constant manner */
566 assign = (assign | (unsigned char)-assign) >> (sizeof( assign ) * 8 - 1);
567 /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
568 limb_mask = -assign;
569
570#if defined(_MSC_VER)
571#pragma warning( pop )
572#endif
573
574 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
575
576 X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign );
577
578 mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign );
579
580 for( i = Y->n; i < X->n; i++ )
581 X->p[i] &= ~limb_mask;
582
583cleanup:
584 return( ret );
585}
586
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200587/*
588 * Conditionally swap X and Y, without leaking information
589 * about whether the swap was made or not.
590 * Here it is not ok to simply swap the pointers, which whould lead to
591 * different memory access patterns when X and Y are used afterwards.
592 */
593int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap )
594{
595 int ret, s;
596 size_t i;
597 mbedtls_mpi_uint limb_mask;
598 mbedtls_mpi_uint tmp;
599 MPI_VALIDATE_RET( X != NULL );
600 MPI_VALIDATE_RET( Y != NULL );
601
602 if( X == Y )
603 return( 0 );
604
605 /* MSVC has a warning about unary minus on unsigned integer types,
606 * but this is well-defined and precisely what we want to do here. */
607#if defined(_MSC_VER)
608#pragma warning( push )
609#pragma warning( disable : 4146 )
610#endif
611
612 /* make sure swap is 0 or 1 in a time-constant manner */
613 swap = (swap | (unsigned char)-swap) >> (sizeof( swap ) * 8 - 1);
614 /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */
615 limb_mask = -swap;
616
617#if defined(_MSC_VER)
618#pragma warning( pop )
619#endif
620
621 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) );
622 MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) );
623
624 s = X->s;
625 X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap );
626 Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap );
627
628
629 for( i = 0; i < X->n; i++ )
630 {
631 tmp = X->p[i];
632 X->p[i] = ( X->p[i] & ~limb_mask ) | ( Y->p[i] & limb_mask );
633 Y->p[i] = ( Y->p[i] & ~limb_mask ) | ( tmp & limb_mask );
634 }
635
636cleanup:
637 return( ret );
638}
639
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200640#endif /* MBEDTLS_BIGNUM_C */