LCOV - code coverage report
Current view: top level - src/common - crypto_p256.c (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.1 % 180 173
Test Date: 2026-01-29 09:48:10 Functions: 100.0 % 24 24
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 84.8 % 46 39

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * Support for EC point decompression on secp256r1 curve.
       3                 :             :  *
       4                 :             :  * Copyright The Mbed TLS Contributors (for all math functions)
       5                 :             :  * Author: Manuel Pégourié-Gonnard.
       6                 :             :  *
       7                 :             :  * Copyright BayLibre SAS (for crypto_p256_uncompress_point())
       8                 :             :  *
       9                 :             :  * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
      10                 :             :  */
      11                 :             : 
      12                 :             : #include <string.h>
      13                 :             : #include <psa/crypto.h>
      14                 :             : #include <edhoc/buffer_sizes.h>
      15                 :             : #include "crypto_p256.h"
      16                 :             : 
      17                 :             : 
      18                 :             : /**********************************************************************
      19                 :             :  *
      20                 :             :  * Operations on fixed-width unsigned integers
      21                 :             :  *
      22                 :             :  * Represented using 32-bit limbs, least significant limb first.
      23                 :             :  * That is: x = x[0] + 2^32 x[1] + ... + 2^224 x[7] for 256-bit.
      24                 :             :  *
      25                 :             :  **********************************************************************/
      26                 :             : 
      27                 :             : /*
      28                 :             :  * 256-bit set to 32-bit value
      29                 :             :  *
      30                 :             :  * in: x in [0, 2^32)
      31                 :             :  * out: z = x
      32                 :             :  */
      33                 :          12 : static void u256_set32(uint32_t z[8], uint32_t x)
      34                 :             : {
      35                 :          12 :         z[0] = x;
      36         [ +  + ]:          96 :         for (unsigned i = 1; i < 8; i++) {
      37                 :          84 :                 z[i] = 0;
      38                 :             :         }
      39                 :          12 : }
      40                 :             : 
      41                 :             : /*
      42                 :             :  * 256-bit addition
      43                 :             :  *
      44                 :             :  * in: x, y in [0, 2^256)
      45                 :             :  * out: z = (x + y) mod 2^256
      46                 :             :  *      c = (x + y) div 2^256
      47                 :             :  * That is, z + c * 2^256 = x + y
      48                 :             :  *
      49                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
      50                 :             :  */
      51                 :          32 : static uint32_t u256_add(uint32_t z[8],
      52                 :             :                                                  const uint32_t x[8], const uint32_t y[8])
      53                 :             : {
      54                 :          32 :         uint32_t carry = 0;
      55                 :             : 
      56         [ +  + ]:         288 :         for (unsigned i = 0; i < 8; i++) {
      57                 :         256 :                 uint64_t sum = (uint64_t) carry + x[i] + y[i];
      58                 :         256 :                 z[i] = (uint32_t) sum;
      59                 :         256 :                 carry = (uint32_t) (sum >> 32);
      60                 :             :         }
      61                 :             : 
      62                 :          32 :         return carry;
      63                 :             : }
      64                 :             : 
      65                 :             : /*
      66                 :             :  * 256-bit subtraction
      67                 :             :  *
      68                 :             :  * in: x, y in [0, 2^256)
      69                 :             :  * out: z = (x - y) mod 2^256
      70                 :             :  *      c = 0 if x >=y, 1 otherwise
      71                 :             :  * That is, z = c * 2^256 + x - y
      72                 :             :  *
      73                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
      74                 :             :  */
      75                 :        1244 : static uint32_t u256_sub(uint32_t z[8],
      76                 :             :                                                  const uint32_t x[8], const uint32_t y[8])
      77                 :             : {
      78                 :        1244 :         uint32_t carry = 0;
      79                 :             : 
      80         [ +  + ]:       11196 :         for (unsigned i = 0; i < 8; i++) {
      81                 :        9952 :                 uint64_t diff = (uint64_t) x[i] - y[i] - carry;
      82                 :        9952 :                 z[i] = (uint32_t) diff;
      83                 :        9952 :                 carry = -(uint32_t) (diff >> 32);
      84                 :             :         }
      85                 :             : 
      86                 :        1244 :         return carry;
      87                 :             : }
      88                 :             : 
      89                 :             : /*
      90                 :             :  * 256-bit conditional assignment
      91                 :             :  *
      92                 :             :  * in: x in [0, 2^256)
      93                 :             :  *     c in [0, 1]
      94                 :             :  * out: z = x if c == 1, z unchanged otherwise
      95                 :             :  *
      96                 :             :  * Note: as a memory area, z must be either equal to x, or not overlap.
      97                 :             :  */
      98                 :        1244 : static void u256_cmov(uint32_t z[8], const uint32_t x[8], uint32_t c)
      99                 :             : {
     100                 :        1244 :         const uint32_t x_mask = -c;
     101         [ +  + ]:       11196 :         for (unsigned i = 0; i < 8; i++) {
     102                 :        9952 :                 z[i] = (z[i] & ~x_mask) | (x[i] & x_mask);
     103                 :             :         }
     104                 :        1244 : }
     105                 :             : 
     106                 :             : /*
     107                 :             :  * 256-bit compare for equality
     108                 :             :  *
     109                 :             :  * in: x in [0, 2^256)
     110                 :             :  *     y in [0, 2^256)
     111                 :             :  * out: 0 if x == y, unspecified non-zero otherwise
     112                 :             :  */
     113                 :           4 : static uint32_t u256_diff(const uint32_t x[8], const uint32_t y[8])
     114                 :             : {
     115                 :           4 :         uint32_t diff = 0;
     116         [ +  + ]:          36 :         for (unsigned i = 0; i < 8; i++) {
     117                 :          32 :                 diff |= x[i] ^ y[i];
     118                 :             :         }
     119                 :           4 :         return diff;
     120                 :             : }
     121                 :             : 
     122                 :             : /*
     123                 :             :  * 32 x 32 -> 64-bit multiply-and-accumulate
     124                 :             :  *
     125                 :             :  * in: x, y, z, t in [0, 2^32)
     126                 :             :  * out: x * y + z + t in [0, 2^64)
     127                 :             :  *
     128                 :             :  * Note: this computation cannot overflow.
     129                 :             :  *
     130                 :             :  * Note: this function has two pure-C implementations (depending on whether
     131                 :             :  * MUL64_IS_CONSTANT_TIME), and possibly optimised asm implementations.
     132                 :             :  * Start with the potential asm definitions, and use the C definition only if
     133                 :             :  * we no have no asm for the current toolchain & CPU.
     134                 :             :  */
     135                 :             : static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t);
     136                 :             : 
     137                 :             : /* This macro is used to mark whether an asm implentation is found */
     138                 :             : #undef MULADD64_ASM
     139                 :             : /* This macro is used to mark whether the implementation has a small
     140                 :             :  * code size (ie, it can be inlined even in an unrolled loop) */
     141                 :             : #undef MULADD64_SMALL
     142                 :             : 
     143                 :             : /*
     144                 :             :  * Currently assembly optimisations are only supported with GCC/Clang for
     145                 :             :  * Arm's Cortex-A and Cortex-M lines of CPUs, which start with the v6-M and
     146                 :             :  * v7-M architectures. __ARM_ARCH_PROFILE is not defined for v6 and earlier.
     147                 :             :  * Thumb and 32-bit assembly is supported; aarch64 is not supported.
     148                 :             :  */
     149                 :             : #if defined(__GNUC__) &&\
     150                 :             :         defined(__ARM_ARCH) && __ARM_ARCH >= 6 && defined(__ARM_ARCH_PROFILE) && \
     151                 :             :         ( __ARM_ARCH_PROFILE == 77 || __ARM_ARCH_PROFILE == 65 ) /* 'M' or 'A' */ && \
     152                 :             :         !defined(__aarch64__)
     153                 :             : 
     154                 :             : /*
     155                 :             :  * This set of CPUs is conveniently partitioned as follows:
     156                 :             :  *
     157                 :             :  * 1. Cores that have the DSP extension, which includes a 1-cycle UMAAL
     158                 :             :  *    instruction: M4, M7, M33, all A-class cores.
     159                 :             :  * 2. Cores that don't have the DSP extension, and also lack a constant-time
     160                 :             :  *    64-bit multiplication instruction:
     161                 :             :  *    - M0, M0+, M23: 32-bit multiplication only;
     162                 :             :  *    - M3: 64-bit multiplication is not constant-time.
     163                 :             :  */
     164                 :             : #if defined(__ARM_FEATURE_DSP)
     165                 :             : 
     166                 :             : static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t)
     167                 :             : {
     168                 :             :         __asm__(
     169                 :             :                 /* UMAAL <RdLo>, <RdHi>, <Rn>, <Rm> */
     170                 :             :                 "umaal   %[z], %[t], %[x], %[y]"
     171                 :             :                 : [z] "+l" (z), [t] "+l" (t)
     172                 :             :                 : [x] "l" (x), [y] "l" (y)
     173                 :             :         );
     174                 :             :         return ((uint64_t) t << 32) | z;
     175                 :             : }
     176                 :             : #define MULADD64_ASM
     177                 :             : #define MULADD64_SMALL
     178                 :             : 
     179                 :             : #else /* __ARM_FEATURE_DSP */
     180                 :             : 
     181                 :             : /*
     182                 :             :  * This implementation only uses 16x16->32 bit multiplication.
     183                 :             :  *
     184                 :             :  * It decomposes the multiplicands as:
     185                 :             :  *      x = xh:xl = 2^16 * xh + xl
     186                 :             :  *      y = yh:yl = 2^16 * yh + yl
     187                 :             :  * and computes their product as:
     188                 :             :  *      x*y = xl*yl + 2**16 (xh*yl + yl*yh) + 2**32 xh*yh
     189                 :             :  * then adds z and t to the result.
     190                 :             :  */
     191                 :             : static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t)
     192                 :             : {
     193                 :             :         /* First compute x*y, using 3 temporary registers */
     194                 :             :         uint32_t tmp1, tmp2, tmp3;
     195                 :             :         __asm__(
     196                 :             :                 ".syntax unified\n\t"
     197                 :             :                 /* start by splitting the inputs into halves */
     198                 :             :                 "lsrs    %[u], %[x], #16\n\t"
     199                 :             :                 "lsrs    %[v], %[y], #16\n\t"
     200                 :             :                 "uxth    %[x], %[x]\n\t"
     201                 :             :                 "uxth    %[y], %[y]\n\t"
     202                 :             :                 /* now we have %[x], %[y], %[u], %[v] = xl, yl, xh, yh */
     203                 :             :                 /* let's compute the 4 products we can form with those */
     204                 :             :                 "movs    %[w], %[v]\n\t"
     205                 :             :                 "muls    %[w], %[u]\n\t"
     206                 :             :                 "muls    %[v], %[x]\n\t"
     207                 :             :                 "muls    %[x], %[y]\n\t"
     208                 :             :                 "muls    %[y], %[u]\n\t"
     209                 :             :                 /* now we have %[x], %[y], %[v], %[w] = xl*yl, xh*yl, xl*yh, xh*yh */
     210                 :             :                 /* let's split and add the first middle product */
     211                 :             :                 "lsls    %[u], %[y], #16\n\t"
     212                 :             :                 "lsrs    %[y], %[y], #16\n\t"
     213                 :             :                 "adds    %[x], %[u]\n\t"
     214                 :             :                 "adcs    %[y], %[w]\n\t"
     215                 :             :                 /* let's finish with the second middle product */
     216                 :             :                 "lsls    %[u], %[v], #16\n\t"
     217                 :             :                 "lsrs    %[v], %[v], #16\n\t"
     218                 :             :                 "adds    %[x], %[u]\n\t"
     219                 :             :                 "adcs    %[y], %[v]\n\t"
     220                 :             :                 : [x] "+l" (x), [y] "+l" (y),
     221                 :             :                   [u] "=&l" (tmp1), [v] "=&l" (tmp2), [w] "=&l" (tmp3)
     222                 :             :                 : /* no read-only inputs */
     223                 :             :                 : "cc"
     224                 :             :         );
     225                 :             :         (void) tmp1;
     226                 :             :         (void) tmp2;
     227                 :             :         (void) tmp3;
     228                 :             : 
     229                 :             :         /* Add z and t, using one temporary register */
     230                 :             :         __asm__(
     231                 :             :                 ".syntax unified\n\t"
     232                 :             :                 "movs    %[u], #0\n\t"
     233                 :             :                 "adds    %[x], %[z]\n\t"
     234                 :             :                 "adcs    %[y], %[u]\n\t"
     235                 :             :                 "adds    %[x], %[t]\n\t"
     236                 :             :                 "adcs    %[y], %[u]\n\t"
     237                 :             :                 : [x] "+l" (x), [y] "+l" (y), [u] "=&l" (tmp1)
     238                 :             :                 : [z] "l" (z), [t] "l" (t)
     239                 :             :                 : "cc"
     240                 :             :         );
     241                 :             :         (void) tmp1;
     242                 :             : 
     243                 :             :         return ((uint64_t) y << 32) | x;
     244                 :             : }
     245                 :             : #define MULADD64_ASM
     246                 :             : 
     247                 :             : #endif /* __ARM_FEATURE_DSP */
     248                 :             : 
     249                 :             : #endif /* GCC/Clang with Cortex-M/A CPU */
     250                 :             : 
     251                 :             : #if !defined(MULADD64_ASM)
     252                 :             : #if defined(MUL64_IS_CONSTANT_TIME)
     253                 :             : static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t)
     254                 :             : {
     255                 :             :         return (uint64_t) x * y + z + t;
     256                 :             : }
     257                 :             : #define MULADD64_SMALL
     258                 :             : #else
     259                 :      153600 : static uint64_t u32_muladd64(uint32_t x, uint32_t y, uint32_t z, uint32_t t)
     260                 :             : {
     261                 :             :         /* x = xl + 2**16 xh, y = yl + 2**16 yh */
     262                 :      153600 :         const uint16_t xl = (uint16_t) x;
     263                 :      153600 :         const uint16_t yl = (uint16_t) y;
     264                 :      153600 :         const uint16_t xh = (uint16_t)(x >> 16);
     265                 :      153600 :         const uint16_t yh = (uint16_t)(y >> 16);
     266                 :             : 
     267                 :             :         /* x*y = xl*yl + 2**16 (xh*yl + yl*yh) + 2**32 xh*yh
     268                 :             :          *     = lo    + 2**16 (m1    + m2   ) + 2**32 hi    */
     269                 :      153600 :         const uint32_t lo = (uint32_t) xl * yl;
     270                 :      153600 :         const uint32_t m1 = (uint32_t) xh * yl;
     271                 :      153600 :         const uint32_t m2 = (uint32_t) xl * yh;
     272                 :      153600 :         const uint32_t hi = (uint32_t) xh * yh;
     273                 :             : 
     274                 :      153600 :         uint64_t acc = lo + ((uint64_t) (hi + (m1 >> 16) + (m2 >> 16)) << 32);
     275                 :      153600 :         acc += m1 << 16;
     276                 :      153600 :         acc += m2 << 16;
     277                 :      153600 :         acc += z;
     278                 :      153600 :         acc += t;
     279                 :             : 
     280                 :      153600 :         return acc;
     281                 :             : }
     282                 :             : #endif /* MUL64_IS_CONSTANT_TIME */
     283                 :             : #endif /* MULADD64_ASM */
     284                 :             : 
     285                 :             : /*
     286                 :             :  * 288 + 32 x 256 -> 288-bit multiply and add
     287                 :             :  *
     288                 :             :  * in: x in [0, 2^32)
     289                 :             :  *     y in [0, 2^256)
     290                 :             :  *     z in [0, 2^288)
     291                 :             :  * out: z_out = z_in + x * y mod 2^288
     292                 :             :  *      c     = z_in + x * y div 2^288
     293                 :             :  * That is, z_out + c * 2^288 = z_in + x * y
     294                 :             :  *
     295                 :             :  * Note: as a memory area, z must be either equal to y, or not overlap.
     296                 :             :  *
     297                 :             :  * This is a helper for Montgomery multiplication.
     298                 :             :  */
     299                 :       19200 : static uint32_t u288_muladd(uint32_t z[9], uint32_t x, const uint32_t y[8])
     300                 :             : {
     301                 :       19200 :         uint32_t carry = 0;
     302                 :             : 
     303                 :             : #define U288_MULADD_STEP(i) \
     304                 :             :         do { \
     305                 :             :                 uint64_t prod = u32_muladd64(x, y[i], z[i], carry); \
     306                 :             :                 z[i] = (uint32_t) prod; \
     307                 :             :                 carry = (uint32_t) (prod >> 32); \
     308                 :             :         } while( 0 )
     309                 :             : 
     310                 :             : #if defined(MULADD64_SMALL)
     311                 :             :         U288_MULADD_STEP(0);
     312                 :             :         U288_MULADD_STEP(1);
     313                 :             :         U288_MULADD_STEP(2);
     314                 :             :         U288_MULADD_STEP(3);
     315                 :             :         U288_MULADD_STEP(4);
     316                 :             :         U288_MULADD_STEP(5);
     317                 :             :         U288_MULADD_STEP(6);
     318                 :             :         U288_MULADD_STEP(7);
     319                 :             : #else
     320         [ +  + ]:      172800 :         for (unsigned i = 0; i < 8; i++) {
     321                 :      153600 :                 U288_MULADD_STEP(i);
     322                 :             :         }
     323                 :             : #endif
     324                 :             : 
     325                 :       19200 :         uint64_t sum = (uint64_t) z[8] + carry;
     326                 :       19200 :         z[8] = (uint32_t) sum;
     327                 :       19200 :         carry = (uint32_t) (sum >> 32);
     328                 :             : 
     329                 :       19200 :         return carry;
     330                 :             : }
     331                 :             : 
     332                 :             : /*
     333                 :             :  * 288-bit in-place right shift by 32 bits
     334                 :             :  *
     335                 :             :  * in: z in [0, 2^288)
     336                 :             :  *     c in [0, 2^32)
     337                 :             :  * out: z_out = z_in div 2^32 + c * 2^256
     338                 :             :  *            = (z_in + c * 2^288) div 2^32
     339                 :             :  *
     340                 :             :  * This is a helper for Montgomery multiplication.
     341                 :             :  */
     342                 :        9600 : static void u288_rshift32(uint32_t z[9], uint32_t c)
     343                 :             : {
     344         [ +  + ]:       86400 :         for (unsigned i = 0; i < 8; i++) {
     345                 :       76800 :                 z[i] = z[i + 1];
     346                 :             :         }
     347                 :        9600 :         z[8] = c;
     348                 :        9600 : }
     349                 :             : 
     350                 :             : /*
     351                 :             :  * 256-bit import from big-endian bytes
     352                 :             :  *
     353                 :             :  * in: p = p0, ..., p31
     354                 :             :  * out: z = p0 * 2^248 + p1 * 2^240 + ... + p30 * 2^8 + p31
     355                 :             :  */
     356                 :          12 : static void u256_from_bytes(uint32_t z[8], const uint8_t p[32])
     357                 :             : {
     358         [ +  + ]:         108 :         for (unsigned i = 0; i < 8; i++) {
     359                 :          96 :                 unsigned j = 4 * (7 - i);
     360                 :          96 :                 z[i] = ((uint32_t) p[j + 0] << 24) |
     361                 :          96 :                            ((uint32_t) p[j + 1] << 16) |
     362                 :          96 :                            ((uint32_t) p[j + 2] <<  8) |
     363                 :          96 :                            ((uint32_t) p[j + 3] <<  0);
     364                 :             :         }
     365                 :          12 : }
     366                 :             : 
     367                 :             : /*
     368                 :             :  * 256-bit export to big-endian bytes
     369                 :             :  *
     370                 :             :  * in: z in [0, 2^256)
     371                 :             :  * out: p = p0, ..., p31 such that
     372                 :             :  *      z = p0 * 2^248 + p1 * 2^240 + ... + p30 * 2^8 + p31
     373                 :             :  */
     374                 :           4 : static void u256_to_bytes(uint8_t p[32], const uint32_t z[8])
     375                 :             : {
     376         [ +  + ]:          36 :         for (unsigned i = 0; i < 8; i++) {
     377                 :          32 :                 unsigned j = 4 * (7 - i);
     378                 :          32 :                 p[j + 0] = (uint8_t) (z[i] >> 24);
     379                 :          32 :                 p[j + 1] = (uint8_t) (z[i] >> 16);
     380                 :          32 :                 p[j + 2] = (uint8_t) (z[i] >>  8);
     381                 :          32 :                 p[j + 3] = (uint8_t) (z[i] >>  0);
     382                 :             :         }
     383                 :           4 : }
     384                 :             : 
     385                 :             : /**********************************************************************
     386                 :             :  *
     387                 :             :  * Operations modulo a 256-bit prime m
     388                 :             :  *
     389                 :             :  * These are done in the Montgomery domain, that is x is represented by
     390                 :             :  *  x * 2^256 mod m
     391                 :             :  * Numbers need to be converted to that domain before computations,
     392                 :             :  * and back from it afterwards.
     393                 :             :  *
     394                 :             :  * Inversion is computed using Fermat's little theorem.
     395                 :             :  *
     396                 :             :  * Assumptions on m:
     397                 :             :  * - Montgomery operations require that m is odd.
     398                 :             :  * - Fermat's little theorem require it to be a prime.
     399                 :             :  * - m256_inv() further requires that m % 2^32 >= 2.
     400                 :             :  * - m256_inv() also assumes that the value of m is not a secret.
     401                 :             :  *
     402                 :             :  * In practice operations are done modulo the curve's p and n,
     403                 :             :  * both of which satisfy those assumptions.
     404                 :             :  *
     405                 :             :  **********************************************************************/
     406                 :             : 
     407                 :             : /*
     408                 :             :  * Data associated to a modulus for Montgomery operations.
     409                 :             :  *
     410                 :             :  * m in [0, 2^256) - the modulus itself, must be odd
     411                 :             :  * R2 = 2^512 mod m
     412                 :             :  * ni = -m^-1 mod 2^32
     413                 :             :  */
     414                 :             : typedef struct {
     415                 :             :         uint32_t m[8];
     416                 :             :         uint32_t R2[8];
     417                 :             :         uint32_t ni;
     418                 :             : }
     419                 :             : m256_mod;
     420                 :             : 
     421                 :             : /*
     422                 :             :  * Data for Montgomery operations modulo the curve's p
     423                 :             :  */
     424                 :             : static const m256_mod p256_p = {
     425                 :             :         {   /* the curve's p */
     426                 :             :                 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
     427                 :             :                 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF,
     428                 :             :         },
     429                 :             :         {   /* 2^512 mod p */
     430                 :             :                 0x00000003, 0x00000000, 0xffffffff, 0xfffffffb,
     431                 :             :                 0xfffffffe, 0xffffffff, 0xfffffffd, 0x00000004,
     432                 :             :         },
     433                 :             :         0x00000001, /* -p^-1 mod 2^32 */
     434                 :             : };
     435                 :             : 
     436                 :             : /*
     437                 :             :  * Modular addition
     438                 :             :  *
     439                 :             :  * in: x, y in [0, m)
     440                 :             :  *     mod must point to a valid m256_mod structure
     441                 :             :  * out: z = (x + y) mod m, in [0, m)
     442                 :             :  *
     443                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
     444                 :             :  */
     445                 :           8 : static void m256_add(uint32_t z[8],
     446                 :             :                                          const uint32_t x[8], const uint32_t y[8],
     447                 :             :                                          const m256_mod *mod)
     448                 :             : {
     449                 :             :         uint32_t r[8];
     450                 :           8 :         uint32_t carry_add = u256_add(z, x, y);
     451                 :           8 :         uint32_t carry_sub = u256_sub(r, z, mod->m);
     452                 :             :         /* Need to subract m if:
     453                 :             :          *      x+y >= 2^256 > m (that is, carry_add == 1)
     454                 :             :          *   OR z >= m (that is, carry_sub == 0) */
     455                 :           8 :         uint32_t use_sub = carry_add | (1 - carry_sub);
     456                 :           8 :         u256_cmov(z, r, use_sub);
     457                 :           8 : }
     458                 :             : 
     459                 :             : /*
     460                 :             :  * Modular addition mod p
     461                 :             :  *
     462                 :             :  * in: x, y in [0, p)
     463                 :             :  * out: z = (x + y) mod p, in [0, p)
     464                 :             :  *
     465                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
     466                 :             :  */
     467                 :           8 : static void m256_add_p(uint32_t z[8],
     468                 :             :                                            const uint32_t x[8], const uint32_t y[8])
     469                 :             : {
     470                 :           8 :         m256_add(z, x, y, &p256_p);
     471                 :           8 : }
     472                 :             : 
     473                 :             : /*
     474                 :             :  * Modular subtraction
     475                 :             :  *
     476                 :             :  * in: x, y in [0, m)
     477                 :             :  *     mod must point to a valid m256_mod structure
     478                 :             :  * out: z = (x - y) mod m, in [0, m)
     479                 :             :  *
     480                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
     481                 :             :  */
     482                 :          24 : static void m256_sub(uint32_t z[8],
     483                 :             :                                          const uint32_t x[8], const uint32_t y[8],
     484                 :             :                                          const m256_mod *mod)
     485                 :             : {
     486                 :             :         uint32_t r[8];
     487                 :          24 :         uint32_t carry = u256_sub(z, x, y);
     488                 :          24 :         (void) u256_add(r, z, mod->m);
     489                 :             :         /* Need to add m if and only if x < y, that is carry == 1.
     490                 :             :          * In that case z is in [2^256 - m + 1, 2^256 - 1], so the
     491                 :             :          * addition will have a carry as well, which cancels out. */
     492                 :          24 :         u256_cmov(z, r, carry);
     493                 :          24 : }
     494                 :             : 
     495                 :             : /*
     496                 :             :  * Modular subtraction mod p
     497                 :             :  *
     498                 :             :  * in: x, y in [0, p)
     499                 :             :  * out: z = (x + y) mod p, in [0, p)
     500                 :             :  *
     501                 :             :  * Note: as a memory area, z must be either equal to x or y, or not overlap.
     502                 :             :  */
     503                 :          24 : static void m256_sub_p(uint32_t z[8],
     504                 :             :                                            const uint32_t x[8], const uint32_t y[8])
     505                 :             : {
     506                 :          24 :         m256_sub(z, x, y, &p256_p);
     507                 :          24 : }
     508                 :             : 
     509                 :             : /*
     510                 :             :  * Montgomery modular multiplication
     511                 :             :  *
     512                 :             :  * in: x, y in [0, m)
     513                 :             :  *     mod must point to a valid m256_mod structure
     514                 :             :  * out: z = (x * y) / 2^256 mod m, in [0, m)
     515                 :             :  *
     516                 :             :  * Note: as a memory area, z may overlap with x or y.
     517                 :             :  */
     518                 :        1200 : static void m256_mul(uint32_t z[8],
     519                 :             :                                          const uint32_t x[8], const uint32_t y[8],
     520                 :             :                                          const m256_mod *mod)
     521                 :             : {
     522                 :             :         /*
     523                 :             :          * Algorithm 14.36 in Handbook of Applied Cryptography with:
     524                 :             :          * b = 2^32, n = 8, R = 2^256
     525                 :             :          */
     526                 :        1200 :         uint32_t m_prime = mod->ni;
     527                 :             :         uint32_t a[9];
     528                 :             : 
     529         [ +  + ]:       12000 :         for (unsigned i = 0; i < 9; i++) {
     530                 :       10800 :                 a[i] = 0;
     531                 :             :         }
     532                 :             : 
     533         [ +  + ]:       10800 :         for (unsigned i = 0; i < 8; i++) {
     534                 :             :                 /* the "mod 2^32" is implicit from the type */
     535                 :        9600 :                 uint32_t u = (a[0] + x[i] * y[0]) * m_prime;
     536                 :             : 
     537                 :             :                 /* a = (a + x[i] * y + u * m) div b */
     538                 :        9600 :                 uint32_t c = u288_muladd(a, x[i], y);
     539                 :        9600 :                 c += u288_muladd(a, u, mod->m);
     540                 :        9600 :                 u288_rshift32(a, c);
     541                 :             :         }
     542                 :             : 
     543                 :             :         /* a = a > m ? a - m : a */
     544                 :        1200 :         uint32_t carry_add = a[8];  // 0 or 1 since a < 2m, see HAC Note 14.37
     545                 :        1200 :         uint32_t carry_sub = u256_sub(z, a, mod->m);
     546                 :        1200 :         uint32_t use_sub = carry_add | (1 - carry_sub);     // see m256_add()
     547                 :        1200 :         u256_cmov(z, a, 1 - use_sub);
     548                 :        1200 : }
     549                 :             : 
     550                 :             : /*
     551                 :             :  * Montgomery modular multiplication modulo p.
     552                 :             :  *
     553                 :             :  * in: x, y in [0, p)
     554                 :             :  * out: z = (x * y) / 2^256 mod p, in [0, p)
     555                 :             :  *
     556                 :             :  * Note: as a memory area, z may overlap with x or y.
     557                 :             :  */
     558                 :        1180 : static void m256_mul_p(uint32_t z[8],
     559                 :             :                                            const uint32_t x[8], const uint32_t y[8])
     560                 :             : {
     561                 :        1180 :         m256_mul(z, x, y, &p256_p);
     562                 :        1180 : }
     563                 :             : 
     564                 :             : /*
     565                 :             :  * In-place conversion to Montgomery form
     566                 :             :  *
     567                 :             :  * in: z in [0, m)
     568                 :             :  *     mod must point to a valid m256_mod structure
     569                 :             :  * out: z_out = z_in * 2^256 mod m, in [0, m)
     570                 :             :  */
     571                 :          16 : static void m256_prep(uint32_t z[8], const m256_mod *mod)
     572                 :             : {
     573                 :          16 :         m256_mul(z, z, mod->R2, mod);
     574                 :          16 : }
     575                 :             : 
     576                 :             : /*
     577                 :             :  * In-place conversion from Montgomery form
     578                 :             :  *
     579                 :             :  * in: z in [0, m)
     580                 :             :  *     mod must point to a valid m256_mod structure
     581                 :             :  * out: z_out = z_in / 2^256 mod m, in [0, m)
     582                 :             :  * That is, z_in was z_actual * 2^256 mod m, and z_out is z_actual
     583                 :             :  */
     584                 :           4 : static void m256_done(uint32_t z[8], const m256_mod *mod)
     585                 :             : {
     586                 :             :         uint32_t one[8];
     587                 :           4 :         u256_set32(one, 1);
     588                 :           4 :         m256_mul(z, z, one, mod);
     589                 :           4 : }
     590                 :             : 
     591                 :             : /*
     592                 :             :  * Set to 32-bit value
     593                 :             :  *
     594                 :             :  * in: x in [0, 2^32)
     595                 :             :  *     mod must point to a valid m256_mod structure
     596                 :             :  * out: z = x * 2^256 mod m, in [0, m)
     597                 :             :  * That is, z is set to the image of x in the Montgomery domain.
     598                 :             :  */
     599                 :           4 : static void m256_set32(uint32_t z[8], uint32_t x, const m256_mod *mod)
     600                 :             : {
     601                 :           4 :         u256_set32(z, x);
     602                 :           4 :         m256_prep(z, mod);
     603                 :           4 : }
     604                 :             : 
     605                 :             : /*
     606                 :             :  * Import modular integer from bytes to Montgomery domain
     607                 :             :  *
     608                 :             :  * in: p = p0, ..., p32
     609                 :             :  *     mod must point to a valid m256_mod structure
     610                 :             :  * out: z = (p0 * 2^248 + ... + p31) * 2^256 mod m, in [0, m)
     611                 :             :  *      return 0 if the number was already in [0, m), or -1.
     612                 :             :  *      z may be incorrect and must be discared when -1 is returned.
     613                 :             :  */
     614                 :          12 : static int m256_from_bytes(uint32_t z[8],
     615                 :             :                                                    const uint8_t p[32], const m256_mod *mod)
     616                 :             : {
     617                 :          12 :         u256_from_bytes(z, p);
     618                 :             : 
     619                 :             :         uint32_t t[8];
     620                 :          12 :         uint32_t lt_m = u256_sub(t, z, mod->m);
     621         [ -  + ]:          12 :         if (lt_m != 1)
     622                 :           0 :                 return -1;
     623                 :             : 
     624                 :          12 :         m256_prep(z, mod);
     625                 :          12 :         return 0;
     626                 :             : }
     627                 :             : 
     628                 :             : /*
     629                 :             :  * Export modular integer from Montgomery domain to bytes
     630                 :             :  *
     631                 :             :  * in: z in [0, 2^256)
     632                 :             :  *     mod must point to a valid m256_mod structure
     633                 :             :  * out: p = p0, ..., p31 such that
     634                 :             :  *      z = (p0 * 2^248 + ... + p31) * 2^256 mod m
     635                 :             :  */
     636                 :           4 : static void m256_to_bytes(uint8_t p[32],
     637                 :             :                                                   const uint32_t z[8], const m256_mod *mod)
     638                 :             : {
     639                 :             :         uint32_t zi[8];
     640                 :           4 :         u256_cmov(zi, z, 1);
     641                 :           4 :         m256_done(zi, mod);
     642                 :             : 
     643                 :           4 :         u256_to_bytes(p, zi);
     644                 :           4 : }
     645                 :             : 
     646                 :             : /**********************************************************************
     647                 :             :  *
     648                 :             :  * Operations on curve points
     649                 :             :  *
     650                 :             :  * Points are represented in two coordinates system:
     651                 :             :  *  - affine (x, y) - extended to represent 0 (see below)
     652                 :             :  *  - jacobian (x:y:z)
     653                 :             :  * In either case, coordinates are integers modulo p256_p and
     654                 :             :  * are always represented in the Montgomery domain.
     655                 :             :  *
     656                 :             :  * For background on jacobian coordinates, see for example [GECC] 3.2.2:
     657                 :             :  * - conversions go (x, y) -> (x:y:1) and (x:y:z) -> (x/z^2, y/z^3)
     658                 :             :  * - the curve equation becomes y^2 = x^3 - 3 x z^4 + b z^6
     659                 :             :  * - 0 (aka the origin aka point at infinity) is (x:y:0) with y^2 = x^3.
     660                 :             :  * - point negation goes -(x:y:z) = (x:-y:z)
     661                 :             :  *
     662                 :             :  * Normally 0 (the point at infinity) can't be represented in affine
     663                 :             :  * coordinates. However we extend affine coordinates with the convention that
     664                 :             :  * (0, 0) (which is normally not a point on the curve) is interpreted as 0.
     665                 :             :  *
     666                 :             :  * References:
     667                 :             :  * - [GECC]: Guide to Elliptic Curve Cryptography; Hankerson, Menezes,
     668                 :             :  *   Vanstone; Springer, 2004.
     669                 :             :  * - [CMO98]: Efficient Elliptic Curve Exponentiation Using Mixed Coordinates;
     670                 :             :  *   Cohen, Miyaji, Ono; Springer, ASIACRYPT 1998.
     671                 :             :  *   https://link.springer.com/content/pdf/10.1007/3-540-49649-1_6.pdf
     672                 :             :  * - [RCB15]: Complete addition formulas for prime order elliptic curves;
     673                 :             :  *   Renes, Costello, Batina; IACR e-print 2015-1060.
     674                 :             :  *   https://eprint.iacr.org/2015/1060.pdf
     675                 :             :  *
     676                 :             :  **********************************************************************/
     677                 :             : 
     678                 :             : /*
     679                 :             :  * The curve's b parameter in the Short Weierstrass equation
     680                 :             :  *  y^2 = x^3 - 3*x + b
     681                 :             :  * Compared to the standard, this is converted to the Montgomery domain.
     682                 :             :  */
     683                 :             : static const uint32_t p256_b[8] = { /* b * 2^256 mod p */
     684                 :             :         0x29c4bddf, 0xd89cdf62, 0x78843090, 0xacf005cd,
     685                 :             :         0xf7212ed6, 0xe5a220ab, 0x04874834, 0xdc30061d,
     686                 :             : };
     687                 :             : 
     688                 :             : /*
     689                 :             :  * Point-on-curve check - do the coordinates satisfy the curve's equation?
     690                 :             :  *
     691                 :             :  * in: x, y in [0, p)   (Montgomery domain)
     692                 :             :  * out: 0 if the point lies on the curve and is not 0,
     693                 :             :  *      unspecified non-zero otherwise
     694                 :             :  */
     695                 :           4 : static uint32_t point_check(const uint32_t x[8], const uint32_t y[8])
     696                 :             : {
     697                 :             :         uint32_t lhs[8], rhs[8];
     698                 :             : 
     699                 :             :         /* lhs = y^2 */
     700                 :           4 :         m256_mul_p(lhs, y, y);
     701                 :             : 
     702                 :             :         /* rhs = x^3 - 3x + b */
     703                 :           4 :         m256_mul_p(rhs, x,   x);      /* x^2 */
     704                 :           4 :         m256_mul_p(rhs, rhs, x);      /* x^3 */
     705         [ +  + ]:          16 :         for (unsigned i = 0; i < 3; i++)
     706                 :          12 :                 m256_sub_p(rhs, rhs, x);  /* x^3 - 3x */
     707                 :           4 :         m256_add_p(rhs, rhs, p256_b); /* x^3 - 3x + b */
     708                 :             : 
     709                 :           4 :         return u256_diff(lhs, rhs);
     710                 :             : }
     711                 :             : 
     712                 :             : /*
     713                 :             :  * Import curve point from bytes
     714                 :             :  *
     715                 :             :  * in: p = (x, y) concatenated, fixed-width 256-bit big-endian integers
     716                 :             :  * out: x, y in Mongomery domain
     717                 :             :  *      return 0 if x and y are both in [0, p)
     718                 :             :  *                  and (x, y) is on the curve and not 0
     719                 :             :  *             unspecified non-zero otherwise.
     720                 :             :  *      x and y are unspecified and must be discarded if returning non-zero.
     721                 :             :  */
     722                 :           4 : static int point_from_bytes(uint32_t x[8], uint32_t y[8], const uint8_t p[64])
     723                 :             : {
     724                 :             :         int ret;
     725                 :             : 
     726                 :           4 :         ret = m256_from_bytes(x, p, &p256_p);
     727         [ -  + ]:           4 :         if (ret != 0)
     728                 :           0 :                 return ret;
     729                 :             : 
     730                 :           4 :         ret = m256_from_bytes(y, p + 32, &p256_p);
     731         [ -  + ]:           4 :         if (ret != 0)
     732                 :           0 :                 return ret;
     733                 :             : 
     734                 :           4 :         return (int) point_check(x, y);
     735                 :             : }
     736                 :             : 
     737                 :           4 : int crypto_p256_uncompress_point(const uint8_t *input, size_t ilen,
     738                 :             :                                  uint8_t *output, size_t *olen, size_t osize)
     739                 :             : {
     740                 :             :         uint32_t x[8], r[8], y2[8];
     741                 :             :         int ret;
     742                 :             : 
     743         [ -  + ]:           4 :         if (ilen != 32) {
     744                 :           0 :                 return PSA_ERROR_INVALID_ARGUMENT;
     745                 :             :         }
     746                 :             : 
     747         [ -  + ]:           4 :         if (osize < 65) {
     748                 :           0 :                 return PSA_ERROR_INVALID_ARGUMENT;
     749                 :             :         }
     750                 :             : 
     751                 :             :         // output will consist of 0x04|X|Y
     752                 :           4 :         *olen = 65;
     753                 :           4 :         output[0] = 0x04;
     754                 :             : 
     755                 :             :         // x <= input
     756         [ -  + ]:           4 :         if (m256_from_bytes(x, input, &p256_p) != 0) {
     757                 :           0 :                 return PSA_ERROR_INVALID_ARGUMENT;
     758                 :             :         }
     759                 :             : 
     760                 :             :         /* r = x^3 - 3x + b */
     761                 :           4 :         m256_mul_p(r, x, x); /* x^2 */
     762                 :           4 :         m256_mul_p(r, r, x); /* x^3 */
     763         [ +  + ]:          16 :         for (unsigned int i = 0; i < 3; i++)
     764                 :          12 :                 m256_sub_p(r, r, x); /* x^3 - 3x */
     765                 :           4 :         m256_add_p(r, r, p256_b); /* x^3 - 3x + b */
     766                 :             :         /* y^2 = r */
     767                 :           4 :         u256_cmov(y2, r, 1);
     768                 :             : 
     769                 :             :         /* exp = (p + 1)/4 = (p + 1) >> 2 */
     770                 :           4 :         uint32_t exp[8] = {
     771                 :             :                 0x00000000, 0x00000000, 0x40000000, 0x00000000,
     772                 :             :                 0x00000000, 0x40000000, 0xC0000000, 0x3FFFFFFF
     773                 :             :         };
     774                 :             : 
     775                 :             :         /* Binary exponentiation */
     776                 :           4 :         m256_set32(r, 1, &p256_p);
     777         [ +  + ]:          36 :         for (uint32_t i = 0; i < 8; i++) {
     778                 :          32 :                 uint32_t exp_limb = exp[i];
     779         [ +  + ]:        1056 :                 for (uint32_t j = 0; j < 32; j++) {
     780         [ +  + ]:        1024 :                         if (exp_limb & 1) {
     781                 :         136 :                                 m256_mul_p(r, r, y2);
     782                 :             :                         }
     783                 :        1024 :                         m256_mul_p(y2, y2, y2);
     784                 :        1024 :                         exp_limb >>= 1;
     785                 :             :                 }
     786                 :             :         }
     787                 :             : 
     788                 :             :         uint32_t y[8], zero[8];
     789                 :           4 :         u256_set32(zero, 0);
     790                 :             :         /* y = r */
     791                 :           4 :         u256_cmov(y, r, 1);
     792                 :             : 
     793                 :             :         uint8_t y_raw[32];
     794                 :           4 :         m256_to_bytes(y_raw, y, &p256_p);
     795                 :             : 
     796                 :             :         uint8_t p[64];
     797                 :             :         uint32_t x_check[8], y_check[8];
     798                 :           4 :         memcpy(p, input, 32);
     799                 :           4 :         memcpy(p + 32, y_raw, 32);
     800                 :           4 :         ret = point_from_bytes(x_check, y_check, p);
     801         [ -  + ]:           4 :         if (ret != 0) {
     802                 :           0 :                 return PSA_ERROR_INVALID_ARGUMENT;
     803                 :             :         }
     804                 :             : 
     805                 :           4 :         memcpy(output + 1, p, 64);
     806                 :             : 
     807                 :           4 :         return 0;
     808                 :             : }
        

Generated by: LCOV version 2.0-1