blob: 8477e182c999a1ef834b53b640472b65d1080687 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/esp32c3-legacy/esp32c3_bignum.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_ESP32C3_BIGNUM_ACCELERATOR
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/param.h>
#include <debug.h>
#include <nuttx/mutex.h>
#include "riscv_internal.h"
#include "hardware/esp32c3_rsa.h"
#include "hardware/esp32c3_system.h"
#include "esp32c3_bignum.h"
/****************************************************************************
* Pre-processor Macros
****************************************************************************/
#define SOC_RSA_MAX_BIT_LEN (3072)
#define CIL (sizeof(uint32_t)) /* chars in limb */
#define BIL (CIL << 3) /* bits in limb */
#define BIH (CIL << 2) /* half limb size */
#define MPI_SIZE_T_MAX ((size_t) -1) /* SIZE_T_MAX is not standard */
/* Convert between bits/chars and number of limbs
* Divide first in order to avoid potential overflows
*/
#define BITS_TO_LIMBS(i) ((i) / BIL + ((i) % BIL != 0))
#define CHARS_TO_LIMBS(i) ((i) / CIL + ((i) % CIL != 0))
/* Get a specific byte, without range checks. */
#define BYTE_BITS (8)
#define BYTE_CHECKS (0xff)
#define GET_BYTE(X, i) (((X)->p[(i) / CIL] >> \
(((i) % CIL) * BYTE_BITS)) & BYTE_CHECKS)
/****************************************************************************
* Private Data
****************************************************************************/
static mutex_t g_rsa_lock = NXMUTEX_INITIALIZER;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_mpi_to_mem_block
*
* Description:
* Copy MPI bignum 'mpi' to hardware memory block.
*
* Input Parameters:
* mem_base - The hardware memory block
* mpi - The bignum 'mpi' from the previous calculation
* num_words - The number of words to be represented
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_to_mem_block(uint32_t mem_base,
const struct esp32c3_mpi_s *mpi,
size_t num_words)
{
uint32_t *pbase = (uint32_t *)mem_base;
uint32_t copy_words = MIN(num_words, mpi->n);
int i;
/* Copy MPI data to memory block registers */
memcpy(pbase, mpi->p, copy_words * sizeof(uint32_t));
/* Zero any remaining memory block data */
for (i = copy_words; i < num_words; i++)
{
pbase[i] = 0;
}
}
/****************************************************************************
* Name: esp32c3_mem_block_to_mpi
*
* Description:
* Read MPI bignum back from hardware memory block.
*
* Input Parameters:
* x - The result from the previous calculation
* mem_base - The hardware memory block
* num_words - The number of words to be represented
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mem_block_to_mpi(struct esp32c3_mpi_s *x,
uint32_t mem_base, int num_words)
{
int i;
/* Copy data from memory block registers */
const size_t REG_WIDTH = sizeof(uint32_t);
for (i = 0; i < num_words; i++)
{
x->p[i] = getreg32(mem_base + (i * REG_WIDTH));
}
/* Zero any remaining limbs in the bignum,
* if the buffer is bigger than num_words
*/
for (i = num_words; i < x->n; i++)
{
x->p[i] = 0;
}
}
/****************************************************************************
* Name: esp32c3_mpi_start_op
*
* Description:
* Begin an RSA operation.
*
* Input Parameters:
* op_reg - Specifies which 'START' register to write to.
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_start_op(uint32_t op_reg)
{
/* Clear interrupt status */
putreg32(1, RSA_CLEAR_INTERRUPT_REG);
/* Note: above putreg32 includes a memw, so we know any writes
* to the memory blocks are also complete.
*/
putreg32(1, op_reg);
}
/****************************************************************************
* Name: esp32c3_mpi_wait_op_complete
*
* Description:
* Wait for an RSA operation to complete.
*
* Input Parameters:
* None
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_wait_op_complete(void)
{
while (getreg32(RSA_IDLE_REG) != 1)
{
}
/* clear the interrupt */
putreg32(1, RSA_CLEAR_INTERRUPT_REG);
}
/****************************************************************************
* Name: esp32c3_mpi_enable_hardware_hw_op
*
* Description:
* Enable the MPI hardware and acquire the lock.
*
* Input Parameters:
* None
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_enable_hardware_hw_op(void)
{
nxmutex_lock(&g_rsa_lock);
/* Enable RSA hardware */
modifyreg32(SYSTEM_PERIP_CLK_EN1_REG, 0, SYSTEM_CRYPTO_RSA_CLK_EN);
modifyreg32(SYSTEM_PERIP_RST_EN1_REG, (SYSTEM_CRYPTO_RSA_RST |
SYSTEM_CRYPTO_DS_RST), 0);
modifyreg32(SYSTEM_RSA_PD_CTRL_REG, SYSTEM_RSA_MEM_PD, 0);
while (getreg32(RSA_CLEAN_REG) != 1)
{
}
}
/****************************************************************************
* Name: esp32c3_mpi_disable_hardware_hw_op
*
* Description:
* Disable the MPI hardware and release the lock.
*
* Input Parameters:
* None
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_disable_hardware_hw_op(void)
{
modifyreg32(SYSTEM_RSA_PD_CTRL_REG, 0, SYSTEM_RSA_MEM_PD);
/* Disable RSA hardware */
modifyreg32(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_CRYPTO_RSA_CLK_EN, 0);
modifyreg32(SYSTEM_PERIP_RST_EN1_REG, 0, SYSTEM_CRYPTO_RSA_RST);
nxmutex_unlock(&g_rsa_lock);
}
/****************************************************************************
* Name: esp32c3_mpi_read_result_hw_op
*
* Description:
* Read out the result from the previous calculation.
*
* Input Parameters:
* Z - The result from the previous calculation
* z_words - The number of words to be represented
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_read_result_hw_op(struct esp32c3_mpi_s *Z,
size_t z_words)
{
esp32c3_mpi_wait_op_complete();
esp32c3_mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_REG, z_words);
}
/****************************************************************************
* Name: esp32c3_mpi_mul_mpi_hw_op
*
* Description:
* Starts a (X * Y) calculation in hardware.
*
* Input Parameters:
* X - First multiplication argument
* Y - Second multiplication argument
* n_words - The number of words to be represented
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_mul_mpi_hw_op(const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
size_t n_words)
{
/* Copy X (right-extended) & Y (left-extended) to memory block */
esp32c3_mpi_to_mem_block(RSA_MEM_X_BLOCK_REG, X, n_words);
esp32c3_mpi_to_mem_block(RSA_MEM_Z_BLOCK_REG + n_words * 4, Y, n_words);
putreg32(((n_words * 2) - 1), RSA_MODE_REG);
esp32c3_mpi_start_op(RSA_MULT_START_REG);
}
/****************************************************************************
* Name: esp32c3_mpi_mult_failover_mod_op
*
* Description:
* Special-case of (X * Y), where we use hardware montgomery mod
* multiplication to calculate result where either A or B are > 2048 bits
* so can't use the standard multiplication method.
*
* Input Parameters:
* X - First multiplication argument
* Y - Second multiplication argument
* num_words - The number of words to be represented
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_mult_failover_mod_op(const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
size_t num_words)
{
int i;
/* M = 2^num_words - 1, so block is entirely FF */
for (i = 0; i < num_words; i++)
{
putreg32(UINT32_MAX, RSA_MEM_M_BLOCK_REG + i * 4);
}
/* mprime = 1 */
putreg32(1, RSA_M_PRIME_REG);
putreg32(num_words - 1, RSA_MODE_REG);
/* Load X & Y */
esp32c3_mpi_to_mem_block(RSA_MEM_X_BLOCK_REG, X, num_words);
esp32c3_mpi_to_mem_block(RSA_MEM_Y_BLOCK_REG, Y, num_words);
/* rinv = 1, write first word */
putreg32(1, RSA_MEM_RB_BLOCK_REG);
/* Zero out rest of the rinv words */
for (i = 1; i < num_words; i++)
{
putreg32(0, RSA_MEM_RB_BLOCK_REG + i * 4);
}
esp32c3_mpi_start_op(RSA_MODMULT_START_REG);
}
/****************************************************************************
* Name: esp32c3_mpi_zeroize
*
* Description:
* Zero any limbs data.
*
* Input Parameters:
* v - The pointer to limbs
* n - The total number of limbs
*
* Returned Value:
* None.
*
****************************************************************************/
static void esp32c3_mpi_zeroize(uint32_t *v, size_t n)
{
memset(v, 0, CIL * n);
}
/****************************************************************************
* Name: bits_to_words
*
* Description:
* Convert bit count to 32-bits word count.
*
* Input Parameters:
* bits - The number of bit count
*
* Returned Value:
* Number of words count.
*
****************************************************************************/
static size_t bits_to_words(size_t bits)
{
return (bits + 31) / 32;
}
/****************************************************************************
* Name: mpi_sub_hlp
*
* Description:
* Helper for esp32c3_mpi subtraction
*
* Input Parameters:
* n - Number of limbs of \p d and \p s
* d - On input, the left operand, On output, the result operand
* s - The right operand
*
* Returned Value:
* \c 1 if \p `d < \p s`.
* \c 0 if \p `d >= \p s`..
*
****************************************************************************/
static uint32_t mpi_sub_hlp(size_t n,
uint32_t *d,
const uint32_t *s)
{
size_t i;
uint32_t c;
uint32_t z;
for (i = c = 0; i < n; i++, s++, d++)
{
z = (*d < c);
*d -= c;
c = (*d < *s) + z;
*d -= *s;
}
return c;
}
/****************************************************************************
* Name: mpi_mul_addc
*
* Description:
* Helper for esp32c3_mpi multiplication
*
* Input Parameters:
* count - The count of limbs
* c - The result number of limbs
* s - The target number of limbs
* d - The pointer to limbs
* b - The total number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static inline void mpi_mul_addc(uint32_t count, uint32_t *c,
uint32_t **s, uint32_t **d, uint32_t b)
{
uint32_t s0;
uint32_t s1;
uint32_t b0;
uint32_t b1;
uint32_t r0;
uint32_t r1;
uint32_t rx;
uint32_t ry;
b0 = (b << BIH) >> BIH;
b1 = (b >> BIH);
for (int i = 0; i < count; ++i)
{
s0 = (**s << BIH) >> BIH;
s1 = (**s >> BIH);
(*s)++;
rx = s0 * b1;
r0 = s0 * b0;
ry = s1 * b0;
r1 = s1 * b1;
r1 += (rx >> BIH);
r1 += (ry >> BIH);
rx <<= BIH;
ry <<= BIH;
r0 += rx;
r1 += (r0 < rx);
r0 += ry;
r1 += (r0 < ry);
r0 += *c;
r1 += (r0 < *c);
r0 += **d;
r1 += (r0 < **d);
*c = r1;
*((*d)++) = r0;
}
}
/****************************************************************************
* Name: mpi_mul_hlp
*
* Description:
* Helper for esp32c3_mpi multiplication
*
* Input Parameters:
* i - The MPI context to grow
* s - The target number of limbs
* d - The pointer to limbs
* b - The total number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static void mpi_mul_hlp(size_t i, uint32_t *s, uint32_t *d, uint32_t b)
{
uint32_t c = 0;
for (; i >= 16; i -= 16)
{
mpi_mul_addc(16, &c, &s, &d, b);
}
for (; i >= 8; i -= 8)
{
mpi_mul_addc(8, &c, &s, &d, b);
}
for (; i > 0; i--)
{
mpi_mul_addc(1, &c, &s, &d, b);
}
do
{
*d += c;
c = (*d < c);
d++;
}
while (c != 0);
}
/****************************************************************************
* Name: mpi_safe_cond_assign
*
* Description:
* Conditionally assign dest = src, without leaking information
* about whether the assignment was made or not.
*
* Input Parameters:
* n - The MPI context to grow
* dest - The MPI to conditionally assign to
* src - The MPI to conditionally assign from
* assign - The condition deciding whether perform the assignment or not
*
* Returned Value:
* None.
*
****************************************************************************/
static void mpi_safe_cond_assign(size_t n,
uint32_t *dest,
const uint32_t *src,
unsigned char assign)
{
size_t i;
for (i = 0; i < n; i++)
{
dest[i] = dest[i] * (1 - assign) + src[i] * assign;
}
}
/****************************************************************************
* Name: mpi_montg_init
*
* Description:
* Fast Montgomery initialization
*
* Input Parameters:
* X - The MPI context to grow
* nblimbs - The target number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static void mpi_montg_init(uint32_t *mm, const struct esp32c3_mpi_s *N)
{
uint32_t x;
uint32_t m0 = N->p[0];
unsigned int i;
x = m0 + (((m0 + 2) & 4) << 1);
for (i = BIL; i >= 8; i /= 2)
{
x *= (2 - (m0 * x));
}
*mm = ~x + 1;
}
/****************************************************************************
* Name: mpi_montmul
*
* Description:
* Montgomery multiplication: A = A * B * R^-1 mod N
*
* Input Parameters:
* A - One of the numbers to multiply,
* It must have at least as many limbs as N
* (A->n >= N->n), and any limbs beyond n are ignored.
* On successful completion, A contains the result of
* the multiplication A * B * R^-1 mod N where
* R = (2^CIL)^n.
* B - One of the numbers to multiply, It must be nonzero
* and must not have more limbs than N (B->n <= N->n)
* N - The modulo. N must be odd.
* mm - The value calculated by `mpi_montg_init(&mm, N)`.
* This is -N^-1 mod 2^CIL.
* T - A bignum for temporary storage.
* It must be at least twice the limb size of N plus 2
* (T->n >= 2 * (N->n + 1)).
*
* Returned Value:
* None.
*
****************************************************************************/
static void mpi_montmul(struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B,
const struct esp32c3_mpi_s *N,
uint32_t mm,
const struct esp32c3_mpi_s *T)
{
size_t i;
size_t n;
size_t m;
uint32_t u0;
uint32_t u1;
uint32_t *d;
memset(T->p, 0, T->n * CIL);
d = T->p;
n = N->n;
m = (B->n < n) ? B->n : n;
for (i = 0; i < n; i++)
{
/* T = (T + u0*B + u1*N) / 2^BIL */
u0 = A->p[i];
u1 = (d[0] + u0 * B->p[0]) * mm;
mpi_mul_hlp(m, B->p, d, u0);
mpi_mul_hlp(n, N->p, d, u1);
*d++ = u0;
d[n + 1] = 0;
}
/* At this point, d is either the desired result or the desired result
* plus N. We now potentially subtract N, avoiding leaking whether the
* subtraction is performed through side channels.
*/
/* Copy the n least significant limbs of d to A, so that
* A = d if d < N (recall that N has n limbs).
*/
memcpy(A->p, d, n * CIL);
/* If d >= N then we want to set A to d - N. To prevent timing attacks,
* do the calculation without using conditional tests.
*/
/* Set d to d0 + (2^BIL)^n - N where d0 is the current value of d.
*/
d[n] += 1;
d[n] -= mpi_sub_hlp(n, d, N->p);
/* If d0 < N then d < (2^BIL)^n
* so d[n] == 0 and we want to keep A as it is.
* If d0 >= N then d >= (2^BIL)^n, and d <= (2^BIL)^n + N < 2 * (2^BIL)^n
* so d[n] == 1 and we want to set A to the result of the subtraction
* which is d - (2^BIL)^n, i.e. the n least significant limbs of d.
* This exactly corresponds to a conditional assignment.
*/
mpi_safe_cond_assign(n, A->p, d, (unsigned char) d[n]);
}
/****************************************************************************
* Name: mpi_montred
*
* Description:
* Montgomery reduction: A = A * R^-1 mod N
*
* Input Parameters:
* A - One of the numbers to multiply,
* It must have at least as many limbs as N
* (A->n >= N->n), and any limbs beyond n are ignored.
* On successful completion, A contains the result of
* the multiplication A * B * R^-1 mod N where
* R = (2^CIL)^n.
* N - The modulo. N must be odd.
* mm - The value calculated by `mpi_montg_init(&mm, N)`.
* This is -N^-1 mod 2^CIL.
* T - A bignum for temporary storage.
* It must be at least twice the limb size of N plus 2
* (T->n >= 2 * (N->n + 1)).
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static void mpi_montred(struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *N,
uint32_t mm,
const struct esp32c3_mpi_s *T)
{
uint32_t z = 1;
struct esp32c3_mpi_s U;
U.n = (int) z;
U.s = (int) z;
U.p = &z;
mpi_montmul(A, &U, N, mm, T);
}
/****************************************************************************
* Name: mpi_mult_mpi_overlong
*
* Description:
* Deal with the case when X & Y are too long for the hardware unit,
* by splitting one operand into two halves.
*
* Input Parameters:
* Z - The destination MPI
* X - The first factor
* Y - The second factor
* y_words - The number of words to be process
* z_words - The number of words to be represented
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int mpi_mult_mpi_overlong(struct esp32c3_mpi_s *Z,
const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
size_t y_words, size_t z_words)
{
int ret = 0;
struct esp32c3_mpi_s ztemp;
/* Rather than slicing in two on bits we slice on limbs (32 bit words) */
const size_t words_slice = y_words / 2;
/* yp holds lower bits of Y */
const struct esp32c3_mpi_s yp = {
.p = Y->p,
.n = words_slice,
.s = Y->s
};
/* ypp holds upper bits of Y,
* right shifted (also reuses Y's array contents)
*/
const struct esp32c3_mpi_s ypp = {
.p = Y->p + words_slice,
.n = y_words - words_slice,
.s = Y->s
};
esp32c3_mpi_init(&ztemp);
/* Get result ztemp = yp * X (need temporary variable ztemp) */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(&ztemp, X, &yp), cleanup);
/* Z = ypp * Y */
ESP32C3_MPI_CHK(esp32c3_mpi_mul_mpi(Z, X, &ypp), cleanup);
/* Z = Z << b */
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(Z, words_slice * 32), cleanup);
/* Z += ztemp */
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(Z, Z, &ztemp), cleanup);
cleanup:
esp32c3_mpi_free(&ztemp);
return ret;
}
/****************************************************************************
* Name: mpi_mult_mpi_failover_mod_mult
*
* Description:
* Where we use hardware montgomery mod multiplication to calculate an
* esp32c3_mpi_mult_mpi result where either A or B are > 2048 bits
* so can't use the standard multiplication method.
*
* Input Parameters:
* Z - The destination MPI
* X - The first factor
* Y - The second factor
* z_words - The number of words to be represented
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int mpi_mult_mpi_failover_mod_mult(struct esp32c3_mpi_s *Z,
const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
size_t z_words)
{
int ret;
esp32c3_mpi_enable_hardware_hw_op();
esp32c3_mpi_mult_failover_mod_op(X, Y, z_words);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(Z, z_words), cleanup);
esp32c3_mpi_read_result_hw_op(Z, z_words);
Z->s = X->s * Y->s;
cleanup:
esp32c3_mpi_disable_hardware_hw_op();
return ret;
}
/****************************************************************************
* Name: esp32c3_bignum_clz
*
* Description:
* Count leading zero bits in a given integer
*
* Input Parameters:
* x - The MPI context to query
*
* Returned Value:
* The count leading zero bits in a given integer.
*
****************************************************************************/
static size_t esp32c3_bignum_clz(const uint32_t x)
{
size_t j;
uint32_t mask = UINT32_C(1) << (BIL - 1);
for (j = 0; j < BIL; j++)
{
if (x & mask)
{
break;
}
mask >>= 1;
}
return j;
}
/****************************************************************************
* Name: mpi_get_digit
*
* Description:
* Convert an ASCII character to digit value
*
* Input Parameters:
* d - The destination MPI
* radix - The numeric base of the input character
* c - An ASCII character
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int mpi_get_digit(uint32_t *d, int radix, char c)
{
*d = 255;
if (c >= 0x30 && c <= 0x39)
{
*d = c - 0x30;
}
if (c >= 0x41 && c <= 0x46)
{
*d = c - 0x37;
}
if (c >= 0x61 && c <= 0x66)
{
*d = c - 0x57;
}
if (*d >= (uint32_t) radix)
{
return ESP32C3_ERR_MPI_INVALID_CHARACTER;
}
return OK;
}
/****************************************************************************
* Name: mpi_write_hlp
*
* Description:
* Helper to write the digits high-order first
*
* Input Parameters:
* X - The source MPI
* radix - The numeric base of the output string
* p - The buffer to write the string to
* buflen - The available size in Bytes of p
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static int mpi_write_hlp(struct esp32c3_mpi_s *X, int radix,
char **p, const size_t buflen)
{
int ret;
uint32_t r;
size_t length = 0;
char *p_end = *p + buflen;
do
{
if (length >= buflen)
{
return ESP32C3_ERR_MPI_BUFFER_TOO_SMALL;
}
ESP32C3_MPI_CHK(esp32c3_mpi_mod_int(&r, X, radix), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_div_int(X, NULL, X, radix), cleanup);
/* Write the residue in the current position, as an ASCII character.
*/
if (r < 0xa)
{
*(--p_end) = (char)('0' + r);
}
else
{
*(--p_end) = (char)('A' + (r - 0xa));
}
length++;
}
while (esp32c3_mpi_cmp_int(X, 0) != 0);
memmove(*p, p_end, length);
*p += length;
cleanup:
return ret;
}
/****************************************************************************
* Name: mpi_uint_bigendian_to_host
*
* Description:
* Convert a big-endian byte array aligned to the size of uint32_t
* into the storage form used by esp32c3_mpi
*
* Input Parameters:
* X - The MPI context to convert
*
* Returned Value:
* The size of uint32_t into the storage form used by esp32c3_mpi.
*
****************************************************************************/
static uint32_t mpi_uint_bigendian_to_host(uint32_t x)
{
uint8_t i;
unsigned char *x_ptr;
uint32_t tmp = 0;
for (i = 0, x_ptr = (unsigned char *) &x; i < CIL; i++, x_ptr++)
{
tmp <<= CHAR_BIT;
tmp |= (uint32_t) *x_ptr;
}
return (tmp);
}
/****************************************************************************
* Name: mpi_bigendian_to_host
*
* Description:
* Enlarge an MPI to the specified number of limbs
*
* Input Parameters:
* p - The MPI context to grow
* limbs - The target number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static void mpi_bigendian_to_host(uint32_t * const p, size_t limbs)
{
uint32_t *cur_limb_left;
uint32_t *cur_limb_right;
if (limbs == 0)
{
return ;
}
/* Traverse limbs and
* - adapt byte-order in each limb
* - swap the limbs themselves.
* For that, simultaneously traverse the limbs from left to right
* and from right to left, as long as the left index is not bigger
* than the right index (it's not a problem if limbs is odd and the
* indices coincide in the last iteration).
*/
for (cur_limb_left = p, cur_limb_right = p + (limbs - 1);
cur_limb_left <= cur_limb_right;
cur_limb_left++, cur_limb_right--)
{
uint32_t tmp;
/* Note that if cur_limb_left == cur_limb_right,
* this code effectively swaps the bytes only once.
*/
tmp = mpi_uint_bigendian_to_host(*cur_limb_left);
*cur_limb_left = mpi_uint_bigendian_to_host(*cur_limb_right);
*cur_limb_right = tmp;
}
}
/****************************************************************************
* Name: ct_lt_mpi_uint
*
* Description:
* Decide if an integer is less than the other, without branches.
*
* Input Parameters:
* X - First integer
* nblimbs - Second integer
*
* Returned Value:
* 1 if \p x is less than \p y, 0 otherwise.
*
****************************************************************************/
static unsigned ct_lt_mpi_uint(const uint32_t x,
const uint32_t y)
{
uint32_t ret;
uint32_t cond;
/* Check if the most significant bits (MSB) of the operands are different.
*/
cond = (x ^ y);
/* If the MSB are the same then the difference x-y will be negative (and
* have its MSB set to 1 during conversion to unsigned) if and only if x<y.
*/
ret = (x - y) & ~cond;
/* If the MSB are different, then the operand with the MSB of 1 is the
* bigger. (That is if y has MSB of 1, then x<y is true and it is false if
* the MSB of y is 0.)
*/
ret |= y & cond;
ret = ret >> (BIL - 1);
return (unsigned) ret;
}
/****************************************************************************
* Name: esp32c3_bignum_int_div_int
*
* Description:
* Unsigned integer divide - double uint32_t dividend, u1/u0, and
* uint32_t divisor, d
*
* Input Parameters:
* X - The MPI context to grow
* nblimbs - The target number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
static uint32_t esp32c3_bignum_int_div_int(uint32_t u1, uint32_t u0,
uint32_t d, uint32_t *r)
{
const uint32_t radix = (uint32_t) 1 << BIH;
const uint32_t uint_halfword_mask = ((uint32_t) 1 << BIH) - 1;
uint32_t d0;
uint32_t d1;
uint32_t q0;
uint32_t q1;
uint32_t rax;
uint32_t r0;
uint32_t quotient;
uint32_t u0_msw;
uint32_t u0_lsw;
size_t s;
/* Check for overflow */
if (0 == d || u1 >= d)
{
if (r != NULL)
{
*r = ~0;
}
return (~0);
}
/* Algorithm D, Section 4.3.1 - The Art of Computer Programming
* Vol. 2 - Seminumerical Algorithms, Knuth
*/
/* Normalize the divisor, d, and dividend, u0, u1
*/
s = esp32c3_bignum_clz(d);
d = d << s;
u1 = u1 << s;
u1 |= (u0 >> (BIL - s)) & (-(int32_t)s >> (BIL - 1));
u0 = u0 << s;
d1 = d >> BIH;
d0 = d & uint_halfword_mask;
u0_msw = u0 >> BIH;
u0_lsw = u0 & uint_halfword_mask;
/* Find the first quotient and remainder
*/
q1 = u1 / d1;
r0 = u1 - d1 * q1;
while (q1 >= radix || (q1 * d0 > radix * r0 + u0_msw))
{
q1 -= 1;
r0 += d1;
if (r0 >= radix)
{
break;
}
}
rax = (u1 * radix) + (u0_msw - q1 * d);
q0 = rax / d1;
r0 = rax - q0 * d1;
while (q0 >= radix || (q0 * d0 > radix * r0 + u0_lsw))
{
q0 -= 1;
r0 += d1;
if (r0 >= radix)
{
break;
}
}
if (r != NULL)
{
*r = (rax * radix + u0_lsw - q0 * d) >> s;
}
quotient = q1 * radix + q0;
return quotient;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32c3_mpi_init
*
* Description:
* Initialize an MPI context
*
* Input Parameters:
* X - The MPI context to initialize
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_mpi_init(struct esp32c3_mpi_s *X)
{
DEBUGASSERT(X != NULL);
X->s = 1;
X->n = 0;
X->p = NULL;
}
/****************************************************************************
* Name: esp32c3_mpi_free
*
* Description:
* Frees the components of an MPI context
*
* Input Parameters:
* X - The MPI context to be cleared
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_mpi_free(struct esp32c3_mpi_s *X)
{
if (X == NULL)
{
return ;
}
if (X->p != NULL)
{
esp32c3_mpi_zeroize(X->p, X->n);
free(X->p);
}
X->s = 1;
X->n = 0;
X->p = NULL;
}
/****************************************************************************
* Name: esp32c3_mpi_grow
*
* Description:
* Enlarge an MPI to the specified number of limbs
*
* Input Parameters:
* X - The MPI context to grow
* nblimbs - The target number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_grow(struct esp32c3_mpi_s *X, size_t nblimbs)
{
uint32_t *p;
DEBUGASSERT(X != NULL);
if (nblimbs > ESP32C3_MPI_MAX_LIMBS)
{
return ESP32C3_ERR_MPI_ALLOC_FAILED;
}
if (X->n < nblimbs)
{
if ((p = calloc(nblimbs, CIL)) == NULL)
{
return ESP32C3_ERR_MPI_ALLOC_FAILED;
}
if (X->p != NULL)
{
memcpy(p, X->p, X->n * CIL);
esp32c3_mpi_zeroize(X->p, X->n);
free(X->p);
}
X->n = nblimbs;
X->p = p;
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_shrink
*
* Description:
* Resizes an MPI downwards, keeping at least the specified number of limbs
*
* Input Parameters:
* X - The MPI context to shrink
* nblimbs - The minimum number of limbs
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_shrink(struct esp32c3_mpi_s *X, size_t nblimbs)
{
uint32_t *p;
size_t i;
DEBUGASSERT(X != NULL);
if (nblimbs > ESP32C3_MPI_MAX_LIMBS)
{
return ESP32C3_ERR_MPI_ALLOC_FAILED;
}
/* Actually resize up if there are currently fewer than nblimbs limbs. */
if (X->n <= nblimbs)
{
return (esp32c3_mpi_grow(X, nblimbs));
}
/* After this point, then X->n > nblimbs and in particular X->n > 0. */
for (i = X->n - 1; i > 0; i--)
{
if (X->p[i] != 0)
{
break;
}
}
i++;
if (i < nblimbs)
{
i = nblimbs;
}
if ((p = calloc(i, CIL)) == NULL)
{
return ESP32C3_ERR_MPI_ALLOC_FAILED;
}
if (X->p != NULL)
{
memcpy(p, X->p, i * CIL);
esp32c3_mpi_zeroize(X->p, X->n);
free(X->p);
}
X->n = i;
X->p = p;
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_copy
*
* Description:
* Copy the contents of Y into X
*
* Input Parameters:
* X - The destination MPI
* Y - The source MPI
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_copy(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y)
{
int ret = 0;
size_t i;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
if (X == Y)
{
return OK;
}
if (Y->n == 0)
{
esp32c3_mpi_free(X);
return OK;
}
for (i = Y->n - 1; i > 0; i--)
{
if (Y->p[i] != 0)
{
break;
}
}
i++;
X->s = Y->s;
if (X->n < i)
{
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, i), cleanup);
}
else
{
memset(X->p + i, 0, (X->n - i) * CIL);
}
memcpy(X->p, Y->p, i * CIL);
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_swap
*
* Description:
* Swap the contents of X and Y
*
* Input Parameters:
* X - The first MPI
* nblimbs - The second MPI
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32c3_mpi_swap(struct esp32c3_mpi_s *X, struct esp32c3_mpi_s *Y)
{
struct esp32c3_mpi_s T;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
memcpy(&T, X, sizeof(struct esp32c3_mpi_s));
memcpy(X, Y, sizeof(struct esp32c3_mpi_s));
memcpy(Y, &T, sizeof(struct esp32c3_mpi_s));
}
/****************************************************************************
* Name: esp32c3_mpi_safe_cond_assign
*
* Description:
* Perform a safe conditional copy of MPI which doesn't
* reveal whether the condition was true or not.
*
* Input Parameters:
* X - The MPI to conditionally assign to
* Y - The MPI to be assigned from
* assign - The condition deciding whether perform the assignment or not
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_safe_cond_assign(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
unsigned char assign)
{
int ret = 0;
size_t i;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
/* make sure assign is 0 or 1 in a time-constant manner */
assign = (assign | (unsigned char)-assign) >> 7;
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, Y->n), cleanup);
X->s = X->s * (1 - assign) + Y->s * assign;
mpi_safe_cond_assign(Y->n, X->p, Y->p, assign);
for (i = Y->n; i < X->n; i++)
{
X->p[i] *= (1 - assign);
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_safe_cond_swap
*
* Description:
* Perform a safe conditional swap which doesn't
* reveal whether the condition was true or not.
*
* Input Parameters:
* X - The first MPI
* Y - The second MPI
* swap - The condition deciding whether to perform the swap or not
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_safe_cond_swap(struct esp32c3_mpi_s *X,
struct esp32c3_mpi_s *Y,
unsigned char swap)
{
int ret;
int s;
size_t i;
uint32_t tmp;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
if (X == Y)
{
return OK;
}
/* make sure swap is 0 or 1 in a time-constant manner */
swap = (swap | (unsigned char)-swap) >> 7;
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, Y->n), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(Y, X->n), cleanup);
s = X->s;
X->s = X->s * (1 - swap) + Y->s * swap;
Y->s = Y->s * (1 - swap) + s * swap;
for (i = 0; i < X->n; i++)
{
tmp = X->p[i];
X->p[i] = X->p[i] * (1 - swap) + Y->p[i] * swap;
Y->p[i] = Y->p[i] * (1 - swap) + tmp * swap;
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_lset
*
* Description:
* Set value from integer
*
* Input Parameters:
* X - The MPI to set
* z - The value to use
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_lset(struct esp32c3_mpi_s *X, int32_t z)
{
int ret;
DEBUGASSERT(X != NULL);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, 1), cleanup);
memset(X->p, 0, X->n * CIL);
X->p[0] = (z < 0) ? -z : z;
X->s = (z < 0) ? -1 : 1;
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_get_bit
*
* Description:
* Get a specific bit from an MPI
*
* Input Parameters:
* X - The MPI context to query
* pos - Zero-based index of the bit to query
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_get_bit(const struct esp32c3_mpi_s *X, size_t pos)
{
DEBUGASSERT(X != NULL);
if (X->n * BIL <= pos)
{
return OK;
}
return ((X->p[pos / BIL] >> (pos % BIL)) & 0x01);
}
/****************************************************************************
* Name: esp32c3_mpi_set_bit
*
* Description:
* Modify a specific bit in an MPI
*
* Input Parameters:
* X - The MPI context to modify
* pos - Zero-based index of the bit to modify
* val - The desired value of bit
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_set_bit(struct esp32c3_mpi_s *X,
size_t pos, unsigned char val)
{
int ret = 0;
size_t off = pos / BIL;
size_t idx = pos % BIL;
DEBUGASSERT(X != NULL);
if (val != 0 && val != 1)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
if (X->n * BIL <= pos)
{
if (val == 0)
{
return OK;
}
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, off + 1), cleanup);
}
X->p[off] &= ~((uint32_t) 0x01 << idx);
X->p[off] |= (uint32_t) val << idx;
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_lsb
*
* Description:
* Return the number of bits of value
*
* Input Parameters:
* X - The MPI context to query
*
* Returned Value:
* The number of bits of value.
*
****************************************************************************/
size_t esp32c3_mpi_lsb(const struct esp32c3_mpi_s *X)
{
size_t i;
size_t j;
size_t count = 0;
DEBUGASSERT(X != NULL);
for (i = 0; i < X->n; i++)
{
for (j = 0; j < BIL; j++, count++)
{
if (((X->p[i] >> j) & 1) != 0)
{
return (count);
}
}
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_bitlen
*
* Description:
* Return the number of bits up to and including the most
* significant bit of value
*
* Input Parameters:
* X - The MPI context to query
*
* Returned Value:
* The number of bits up and including the most significant bit of value.
*
****************************************************************************/
size_t esp32c3_mpi_bitlen(const struct esp32c3_mpi_s *X)
{
size_t i;
size_t j;
if (X->n == 0)
{
return OK;
}
for (i = X->n - 1; i > 0; i--)
{
if (X->p[i] != 0)
{
break;
}
}
j = BIL - esp32c3_bignum_clz(X->p[i]);
return ((i * BIL) + j);
}
/****************************************************************************
* Name: esp32c3_mpi_size
*
* Description:
* Return the total size of an MPI value in bytes
*
* Input Parameters:
* X - The MPI context to query
*
* Returned Value:
* The least number of bytes capable of storing the absolute value.
*
****************************************************************************/
size_t esp32c3_mpi_size(const struct esp32c3_mpi_s *X)
{
return ((esp32c3_mpi_bitlen(X) + 7) >> 3);
}
/****************************************************************************
* Name: esp32c3_mpi_read_string
*
* Description:
* Import from an ASCII string
*
* Input Parameters:
* X - The destination MPI
* radix - The numeric base of the input string
* s - Null-terminated string buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_read_string(struct esp32c3_mpi_s *X,
int radix, const char *s)
{
int ret;
size_t i;
size_t j;
size_t slen;
size_t n;
uint32_t d;
struct esp32c3_mpi_s T;
DEBUGASSERT(X != NULL);
DEBUGASSERT(s != NULL);
if (radix < 2 || radix > 16)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
esp32c3_mpi_init(&T);
slen = strlen(s);
if (radix == 16)
{
if (slen > MPI_SIZE_T_MAX >> 2)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
n = BITS_TO_LIMBS(slen << 2);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, n), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(X, 0), cleanup);
for (i = slen, j = 0; i > 0; i--, j++)
{
if (i == 1 && s[i - 1] == '-')
{
X->s = -1;
break;
}
ESP32C3_MPI_CHK(mpi_get_digit(&d, radix, s[i - 1]), cleanup);
X->p[j / (2 * CIL)] |= d << ((j % (2 * CIL)) << 2);
}
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_lset(X, 0), cleanup);
for (i = 0; i < slen; i++)
{
if (i == 0 && s[i] == '-')
{
X->s = -1;
continue;
}
ESP32C3_MPI_CHK(mpi_get_digit(&d, radix, s[i]), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_int(&T, X, radix), cleanup);
if (X->s == 1)
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_int(X, &T, d), cleanup);
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_int(X, &T, d), cleanup);
}
}
}
cleanup:
esp32c3_mpi_free(&T);
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_write_string
*
* Description:
* Export an MPI to an ASCII string
*
* Input Parameters:
* X - The source MPI
* radix - The numeric base of the output string
* buf - The buffer to write the string to
* buflen - The available size in Bytes of buf
* olen - The address at which to store the length of the string written
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_write_string(const struct esp32c3_mpi_s *X, int radix,
char *buf, size_t buflen, size_t *olen)
{
int ret = 0;
size_t n;
char *p;
struct esp32c3_mpi_s T;
DEBUGASSERT(X != NULL);
DEBUGASSERT(olen != NULL);
DEBUGASSERT(buflen == 0 || buf != NULL);
if (radix < 2 || radix > 16)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
/* Number of bits necessary to present `n`. */
n = esp32c3_mpi_bitlen(X);
if (radix >= 4)
{
/* Number of 4-adic digits necessary to present
* `n`. If radix > 4, this might be a strict
* overapproximation of the number of
* radix-adic digits needed to present `n`.
*/
n >>= 1;
}
if (radix >= 16)
{
/* Number of hexadecimal digits necessary to
* present `n`.
*/
n >>= 1;
}
/* Terminating null byte */
n += 1;
/* Compensate for the divisions above, which round down `n`
* in case it's not even.
*/
n += 1;
/* Potential '-'-sign. */
n += 1;
/* Make n even to have enough space for hexadecimal writing,
* which always uses an even number of hex-digits.
*/
n += (n & 1);
if (buflen < n)
{
*olen = n;
return ESP32C3_ERR_MPI_BUFFER_TOO_SMALL;
}
p = buf;
esp32c3_mpi_init(&T);
if (X->s == -1)
{
*p++ = '-';
buflen--;
}
if (radix == 16)
{
int c;
size_t i;
size_t j;
size_t k;
for (i = X->n, k = 0; i > 0; i--)
{
for (j = CIL; j > 0; j--)
{
c = (X->p[i - 1] >> ((j - 1) << 3)) & 0xff;
if (c == 0 && k == 0 && (i + j) != 2)
{
continue;
}
*(p++) = "0123456789ABCDEF" [c / 16];
*(p++) = "0123456789ABCDEF" [c % 16];
k = 1;
}
}
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&T, X), cleanup);
if (T.s == -1)
{
T.s = 1;
}
ESP32C3_MPI_CHK(mpi_write_hlp(&T, radix, &p, buflen), cleanup);
}
*p++ = '\0';
*olen = p - buf;
cleanup:
esp32c3_mpi_free(&T);
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_read_binary
*
* Description:
* Import an MPI from unsigned big endian binary data
*
* Input Parameters:
* X - The destination MPI
* buf - The input buffer
* buflen - The length of the input buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_read_binary(struct esp32c3_mpi_s *X,
const unsigned char *buf,
size_t buflen)
{
int ret;
size_t const limbs = CHARS_TO_LIMBS(buflen);
size_t const overhead = (limbs * CIL) - buflen;
unsigned char *XP;
DEBUGASSERT(X != NULL);
DEBUGASSERT(buflen == 0 || buf != NULL);
/* Ensure that target MPI has exactly the necessary number of limbs */
if (X->n != limbs)
{
esp32c3_mpi_free(X);
esp32c3_mpi_init(X);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, limbs), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_lset(X, 0), cleanup);
/* Avoid calling `memcpy` with NULL source argument,
* even if buflen is 0.
*/
if (buf != NULL)
{
XP = (unsigned char *) X->p;
memcpy(XP + overhead, buf, buflen);
mpi_bigendian_to_host(X->p, limbs);
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_write_binary
*
* Description:
* Export X into unsigned binary data, big endian
*
* Input Parameters:
* X - The source MPI
* buf - The output buffer
* buflen - The length of the output buffer
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_write_binary(const struct esp32c3_mpi_s *X,
unsigned char *buf, size_t buflen)
{
size_t stored_bytes;
size_t bytes_to_copy;
unsigned char *p;
size_t i;
DEBUGASSERT(X != NULL);
DEBUGASSERT(buflen == 0 || buf != NULL);
stored_bytes = X->n * CIL;
if (stored_bytes < buflen)
{
/* There is enough space in the output buffer. Write initial
* null bytes and record the position at which to start
* writing the significant bytes. In this case, the execution
* trace of this function does not depend on the value of the
* number.
*/
bytes_to_copy = stored_bytes;
p = buf + buflen - stored_bytes;
memset(buf, 0, buflen - stored_bytes);
}
else
{
/* The output buffer is smaller than the allocated size of X.
* However X may fit if its leading bytes are zero.
*/
bytes_to_copy = buflen;
p = buf;
for (i = bytes_to_copy; i < stored_bytes; i++)
{
if (GET_BYTE(X, i) != 0)
{
return ESP32C3_ERR_MPI_BUFFER_TOO_SMALL;
}
}
}
for (i = 0; i < bytes_to_copy; i++)
{
p[bytes_to_copy - i - 1] = GET_BYTE(X, i);
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_shift_l
*
* Description:
* Perform a left-shift on an MPI: X <<= count
*
* Input Parameters:
* X - The MPI to shift
* count - The number of bits to shift by
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_shift_l(struct esp32c3_mpi_s *X, size_t count)
{
int ret;
size_t i;
size_t v0;
size_t t1;
uint32_t r0 = 0;
uint32_t r1;
DEBUGASSERT(X != NULL);
v0 = count / (BIL);
t1 = count & (BIL - 1);
i = esp32c3_mpi_bitlen(X) + count;
if (X->n * BIL < i)
{
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, BITS_TO_LIMBS(i)), cleanup);
}
ret = 0;
/* shift by count / limb_size */
if (v0 > 0)
{
for (i = X->n; i > v0; i--)
X->p[i - 1] = X->p[i - v0 - 1];
for (; i > 0; i--)
X->p[i - 1] = 0;
}
/* shift by count % limb_size
*/
if (t1 > 0)
{
for (i = v0; i < X->n; i++)
{
r1 = X->p[i] >> (BIL - t1);
X->p[i] <<= t1;
X->p[i] |= r0;
r0 = r1;
}
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_shift_r
*
* Description:
* Perform a right-shift on an MPI: X >>= count
*
* Input Parameters:
* X - The MPI to shift
* count - The number of bits to shift by
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_shift_r(struct esp32c3_mpi_s *X, size_t count)
{
size_t i;
size_t v0;
size_t v1;
uint32_t r0 = 0;
uint32_t r1;
DEBUGASSERT(X != NULL);
v0 = count / BIL;
v1 = count & (BIL - 1);
if (v0 > X->n || (v0 == X->n && v1 > 0))
{
return esp32c3_mpi_lset(X, 0);
}
/* shift by count / limb_size
*/
if (v0 > 0)
{
for (i = 0; i < X->n - v0; i++)
{
X->p[i] = X->p[i + v0];
}
for (; i < X->n; i++)
{
X->p[i] = 0;
}
}
/* shift by count % limb_size
*/
if (v1 > 0)
{
for (i = X->n; i > 0; i--)
{
r1 = X->p[i - 1] << (BIL - v1);
X->p[i - 1] >>= v1;
X->p[i - 1] |= r0;
r0 = r1;
}
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_cmp_abs
*
* Description:
* Compare the absolute values of two MPIs
*
* Input Parameters:
* X - The left-hand MPI
* Y - The right-hand MPI
*
* Returned Value:
* 1 if \p `|X|` is greater than \p `|Y|`.
* -1 if \p `|X|` is lesser than \p `|Y|`.
* 0 if \p `|X|` is equal to \p `|Y|`.
*
****************************************************************************/
int esp32c3_mpi_cmp_abs(const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y)
{
size_t i;
size_t j;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
for (i = X->n; i > 0; i--)
{
if (X->p[i - 1] != 0)
{
break;
}
}
for (j = Y->n; j > 0; j--)
{
if (Y->p[j - 1] != 0)
{
break;
}
}
if (i == 0 && j == 0)
{
return OK;
}
if (i > j)
{
return (1);
}
if (j > i)
{
return (-1);
}
for (; i > 0; i--)
{
if (X->p[i - 1] > Y->p[i - 1])
{
return (1);
}
if (X->p[i - 1] < Y->p[i - 1])
{
return (-1);
}
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_cmp_mpi
*
* Description:
* Compare two MPIs.
*
* Input Parameters:
* X - The left-hand MPI
* Y - The right-hand MPI
*
* Returned Value:
* 1 if \p `X` is greater than \p `Y`.
* -1 if \p `X` is lesser than \p `Y`.
* 0 if \p `X` is equal to \p `Y`.
*
****************************************************************************/
int esp32c3_mpi_cmp_mpi(const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y)
{
size_t i;
size_t j;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
for (i = X->n; i > 0; i--)
{
if (X->p[i - 1] != 0)
{
break;
}
}
for (j = Y->n; j > 0; j--)
{
if (Y->p[j - 1] != 0)
{
break;
}
}
if (i == 0 && j == 0)
{
return OK;
}
if (i > j)
{
return (X->s);
}
if (j > i)
{
return (-Y->s);
}
if (X->s > 0 && Y->s < 0)
{
return (1);
}
if (Y->s > 0 && X->s < 0)
{
return (-1);
}
for (; i > 0; i--)
{
if (X->p[i - 1] > Y->p[i - 1])
{
return (X->s);
}
if (X->p[i - 1] < Y->p[i - 1])
{
return (-X->s);
}
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_lt_mpi_ct
*
* Description:
* Check if an MPI is less than the other in constant time
*
* Input Parameters:
* X - The left-hand MPI
* Y - The right-hand MPI
* ret - The result of the comparison:
* 1 if \p X is less than \p Y.
* 0 if \p X is greater than or equal to \p Y.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_lt_mpi_ct(const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y,
unsigned *ret)
{
size_t i;
/* The value of any of these variables is either 0 or 1 at all times. */
unsigned cond;
unsigned done;
unsigned x_is_negative;
unsigned y_is_negative;
DEBUGASSERT(X != NULL);
DEBUGASSERT(Y != NULL);
DEBUGASSERT(ret != NULL);
if (X->n != Y->n)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
/* Set sign_N to 1 if N >= 0, 0 if N < 0.
* We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
*/
x_is_negative = (X->s & 2) >> 1;
y_is_negative = (Y->s & 2) >> 1;
/* If the signs are different, then the positive operand is the bigger.
* That is if X is negative (x_is_negative == 1), then X < Y is true and it
* is false if X is positive (x_is_negative == 0).
*/
cond = (x_is_negative ^ y_is_negative);
*ret = cond & x_is_negative;
/* This is a constant-time function. We might have the result, but we still
* need to go through the loop. Record if we have the result already.
*/
done = cond;
for (i = X->n; i > 0; i--)
{
/* If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
* X and Y are negative.
*
* Again even if we can make a decision, we just mark the result and
* the fact that we are done and continue looping.
*/
cond = ct_lt_mpi_uint(Y->p[i - 1], X->p[i - 1]);
*ret |= cond & (1 - done) & x_is_negative;
done |= cond;
/* If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
* X and Y are positive.
*
* Again even if we can make a decision, we just mark the result and
* the fact that we are done and continue looping.
*/
cond = ct_lt_mpi_uint(X->p[i - 1], Y->p[i - 1]);
*ret |= cond & (1 - done) & (1 - x_is_negative);
done |= cond;
}
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_cmp_int
*
* Description:
* Compare an MPI with an integer
*
* Input Parameters:
* X - The left-hand MPI
* z - The integer value to compare \p X to
*
* Returned Value:
* \c 1 if \p X is greater than \p z.
* \c -1 if \p X is lesser than \p z.
* \c 0 if \p X is equal to \p z.
*
****************************************************************************/
int esp32c3_mpi_cmp_int(const struct esp32c3_mpi_s *X, int32_t z)
{
struct esp32c3_mpi_s Y;
uint32_t p[1];
DEBUGASSERT(X != NULL);
*p = (z < 0) ? -z : z;
Y.s = (z < 0) ? -1 : 1;
Y.n = 1;
Y.p = p;
return (esp32c3_mpi_cmp_mpi(X, &Y));
}
/****************************************************************************
* Name: esp32c3_mpi_add_abs
*
* Description:
* Perform an unsigned addition of MPIs: X = |A| + |B|
*
* Input Parameters:
* X - The left-hand MPI
* z - The integer value to compare \p X to.
*
* Returned Value:
* \c 1 if \p X is greater than \p z.
* \c -1 if \p X is lesser than \p z.
* \c 0 if \p X is equal to \p z.
*
****************************************************************************/
int esp32c3_mpi_add_abs(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
size_t i;
size_t j;
uint32_t *o;
uint32_t *p;
uint32_t c;
uint32_t tmp;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
if (X == B)
{
const struct esp32c3_mpi_s *T = A; A = X; B = T;
}
if (X != A)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(X, A), cleanup);
}
/* X should always be positive as a result of unsigned additions.
*/
X->s = 1;
for (j = B->n; j > 0; j--)
{
if (B->p[j - 1] != 0)
{
break;
}
}
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, j), cleanup);
o = B->p; p = X->p; c = 0;
/* tmp is used because it might happen that p == o
*/
for (i = 0; i < j; i++, o++, p++)
{
tmp = *o;
*p += c; c = (*p < c);
*p += tmp; c += (*p < tmp);
}
while (c != 0)
{
if (i >= X->n)
{
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, i + 1), cleanup);
p = X->p + i;
}
*p += c; c = (*p < c); i++; p++;
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_sub_abs
*
* Description:
* Perform an unsigned subtraction of MPIs: X = |A| - |B|
*
* Input Parameters:
* X - The destination MPI
* A - The minuend
* B - The subtrahend
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_sub_abs(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
struct esp32c3_mpi_s TB;
int ret;
size_t n;
uint32_t carry;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
esp32c3_mpi_init(&TB);
if (X == B)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TB, B), cleanup);
B = &TB;
}
if (X != A)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(X, A), cleanup);
}
/* X should always be positive as a result of unsigned subtractions. */
X->s = 1;
ret = 0;
for (n = B->n; n > 0; n--)
{
if (B->p[n - 1] != 0)
{
break;
}
}
carry = mpi_sub_hlp(n, X->p, B->p);
if (carry != 0)
{
/* Propagate the carry to the first nonzero limb of X. */
for (; n < X->n && X->p[n] == 0; n++)
{
--X->p[n];
}
/* If we ran out of space for the carry, it means that the result
* is negative.
*/
if (n == X->n)
{
ret = ESP32C3_ERR_MPI_NEGATIVE_VALUE;
goto cleanup;
}
--X->p[n];
}
cleanup:
esp32c3_mpi_free(&TB);
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_add_mpi
*
* Description:
* Perform a signed addition of MPIs: X = A + B
*
* Input Parameters:
* X - The destination MPI
* A - The first summand
* B - The second summand
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_add_mpi(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
int s;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
s = A->s;
if (A->s * B->s < 0)
{
if (esp32c3_mpi_cmp_abs(A, B) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(X, A, B), cleanup);
X->s = s;
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(X, B, A), cleanup);
X->s = -s;
}
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_abs(X, A, B), cleanup);
X->s = s;
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_sub_mpi
*
* Description:
* Perform a signed subtraction of MPIs: X = A - B
*
* Input Parameters:
* X - The destination MPI
* A - The minuend
* B - The subtrahend
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_sub_mpi(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
int s;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
s = A->s;
if (A->s * B->s > 0)
{
if (esp32c3_mpi_cmp_abs(A, B) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(X, A, B), cleanup);
X->s = s;
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(X, B, A), cleanup);
X->s = -s;
}
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_abs(X, A, B), cleanup);
X->s = s;
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_add_int
*
* Description:
* Perform a signed addition of an MPI and an integer: X = A + b
*
* Input Parameters:
* X - The destination MPI
* A - The first summand
* b - The second summand
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_add_int(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
int32_t b)
{
struct esp32c3_mpi_s _B;
uint32_t p[1];
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
p[0] = (b < 0) ? -b : b;
_B.s = (b < 0) ? -1 : 1;
_B.n = 1;
_B.p = p;
return (esp32c3_mpi_add_mpi(X, A, &_B));
}
/****************************************************************************
* Name: esp32c3_mpi_sub_int
*
* Description:
* Perform a signed subtraction of an MPI and an integer: X = A - b
*
* Input Parameters:
* X - The destination MPI
* A - The minuend
* b - The subtrahend
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_sub_int(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
int32_t b)
{
struct esp32c3_mpi_s _B;
uint32_t p[1];
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
p[0] = (b < 0) ? -b : b;
_B.s = (b < 0) ? -1 : 1;
_B.n = 1;
_B.p = p;
return (esp32c3_mpi_sub_mpi(X, A, &_B));
}
/****************************************************************************
* Name: esp32c3_mpi_mul_mpi
*
* Description:
* Perform a multiplication of two MPIs: Z = X * Y
*
* Input Parameters:
* Z - The destination MPI
* X - The first factor
* Y - The second factor
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_mul_mpi(struct esp32c3_mpi_s *Z,
const struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *Y)
{
int ret = 0;
size_t x_bits = esp32c3_mpi_bitlen(X);
size_t y_bits = esp32c3_mpi_bitlen(Y);
size_t x_words = bits_to_words(x_bits);
size_t y_words = bits_to_words(y_bits);
size_t z_words = bits_to_words(x_bits + y_bits);
size_t hw_words = MAX(x_words, y_words);
/* Short-circuit eval if either argument is 0 or 1.
* This is needed as the mpi modular division
* argument will sometimes call in here when one
* argument is too large for the hardware unit, but the other
* argument is zero or one.
*/
if (x_bits == 0 || y_bits == 0)
{
esp32c3_mpi_lset(Z, 0);
return 0;
}
if (x_bits == 1)
{
ret = esp32c3_mpi_copy(Z, Y);
Z->s *= X->s;
return ret;
}
if (y_bits == 1)
{
ret = esp32c3_mpi_copy(Z, X);
Z->s *= Y->s;
return ret;
}
/* Grow Z to result size early, avoid interim allocations */
ESP32C3_MPI_CHK(esp32c3_mpi_grow(Z, z_words), cleanup);
/* If factor is over 2048 bits, we can't use the standard
* hardware multiplier
*/
if (hw_words * 32 > SOC_RSA_MAX_BIT_LEN / 2)
{
if (z_words * 32 <= SOC_RSA_MAX_BIT_LEN)
{
return mpi_mult_mpi_failover_mod_mult(Z, X, Y, z_words);
}
else
{
/* Still too long for the hardware unit... */
if (y_words > x_words)
{
return mpi_mult_mpi_overlong(Z, X, Y, y_words, z_words);
}
else
{
return mpi_mult_mpi_overlong(Z, Y, X, x_words, z_words);
}
}
}
/* Otherwise, we can use the (faster) multiply hardware unit */
esp32c3_mpi_enable_hardware_hw_op();
esp32c3_mpi_mul_mpi_hw_op(X, Y, hw_words);
esp32c3_mpi_read_result_hw_op(Z, z_words);
esp32c3_mpi_disable_hardware_hw_op();
Z->s = X->s * Y->s;
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_mul_int
*
* Description:
* Perform a multiplication of an MPI with an unsigned integer: X = A * b
*
* Input Parameters:
* X - The destination MPI
* A - The first factor
* b - The second factor.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_mul_int(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
uint32_t b)
{
struct esp32c3_mpi_s _B;
uint32_t p[1];
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
_B.s = 1;
_B.n = 1;
_B.p = p;
p[0] = b;
return (esp32c3_mpi_mul_mpi(X, A, &_B));
}
/****************************************************************************
* Name: esp32c3_mpi_div_mpi
*
* Description:
* Perform a division with remainder of two MPIs: A = Q * B + R
*
* Input Parameters:
* Q - The destination MPI for the quotient
* R - The destination MPI for the remainder value
* A - The dividend
* B - The divisor
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_div_mpi(struct esp32c3_mpi_s *Q,
struct esp32c3_mpi_s *R,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
size_t i;
size_t n;
size_t t;
size_t k;
struct esp32c3_mpi_s X;
struct esp32c3_mpi_s Y;
struct esp32c3_mpi_s Z;
struct esp32c3_mpi_s T1;
struct esp32c3_mpi_s T2;
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
if (esp32c3_mpi_cmp_int(B, 0) == 0)
{
return ESP32C3_ERR_MPI_DIVISION_BY_ZERO;
}
esp32c3_mpi_init(&X);
esp32c3_mpi_init(&Y);
esp32c3_mpi_init(&Z);
esp32c3_mpi_init(&T1);
esp32c3_mpi_init(&T2);
if (esp32c3_mpi_cmp_abs(A, B) < 0)
{
if (Q != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_lset(Q, 0), cleanup);
}
if (R != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(R, A), cleanup);
}
return OK;
}
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&X, A), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&Y, B), cleanup);
X.s = Y.s = 1;
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&Z, A->n + 2), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&Z, 0), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&T1, 2), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&T2, 3), cleanup);
k = esp32c3_mpi_bitlen(&Y) % BIL;
if (k < BIL - 1)
{
k = BIL - 1 - k;
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&X, k), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&Y, k), cleanup);
}
else
{
k = 0;
}
n = X.n - 1;
t = Y.n - 1;
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&Y, BIL * (n - t)), cleanup);
while (esp32c3_mpi_cmp_mpi(&X, &Y) >= 0)
{
Z.p[n - t]++;
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&X, &X, &Y), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&Y, BIL * (n - t)), cleanup);
for (i = n; i > t ; i--)
{
if (X.p[i] >= Y.p[t])
{
Z.p[i - t - 1] = ~0;
}
else
{
Z.p[i - t - 1] = esp32c3_bignum_int_div_int(X.p[i], X.p[i - 1],
Y.p[t], NULL);
}
Z.p[i - t - 1]++;
do
{
Z.p[i - t - 1]--;
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&T1, 0), cleanup);
T1.p[0] = (t < 1) ? 0 : Y.p[t - 1];
T1.p[1] = Y.p[t];
ESP32C3_MPI_CHK(esp32c3_mpi_mul_int(&T1, &T1, Z.p[i - t - 1]),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&T2, 0), cleanup);
T2.p[0] = (i < 2) ? 0 : X.p[i - 2];
T2.p[1] = (i < 1) ? 0 : X.p[i - 1];
T2.p[2] = X.p[i];
}
while (esp32c3_mpi_cmp_mpi(&T1, &T2) > 0);
ESP32C3_MPI_CHK(esp32c3_mpi_mul_int(&T1, &Y, Z.p[i - t - 1]), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&T1, BIL * (i - t - 1)), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&X, &X, &T1), cleanup);
if (esp32c3_mpi_cmp_int(&X, 0) < 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&T1, &Y), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&T1, BIL * (i - t - 1)),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&X, &X, &T1), cleanup);
Z.p[i - t - 1]--;
}
}
if (Q != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(Q, &Z), cleanup);
Q->s = A->s * B->s;
}
if (R != NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&X, k), cleanup);
X.s = A->s;
ESP32C3_MPI_CHK(esp32c3_mpi_copy(R, &X), cleanup);
if (esp32c3_mpi_cmp_int(R, 0) == 0)
{
R->s = 1;
}
}
cleanup:
esp32c3_mpi_free(&X); esp32c3_mpi_free(&Y); esp32c3_mpi_free(&Z);
esp32c3_mpi_free(&T1); esp32c3_mpi_free(&T2);
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_div_int
*
* Description:
* Perform a division with remainder of an MPI by an integer: A = Q * b + R
*
* Input Parameters:
* Q - The destination MPI for the quotient
* R - The destination MPI for the remainder value
* A - The dividend
* B - The divisor
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_div_int(struct esp32c3_mpi_s *Q,
struct esp32c3_mpi_s *R,
const struct esp32c3_mpi_s *A,
int32_t b)
{
struct esp32c3_mpi_s _B;
uint32_t p[1];
DEBUGASSERT(A != NULL);
p[0] = (b < 0) ? -b : b;
_B.s = (b < 0) ? -1 : 1;
_B.n = 1;
_B.p = p;
return (esp32c3_mpi_div_mpi(Q, R, A, &_B));
}
/****************************************************************************
* Name: esp32c3_mpi_mod_mpi
*
* Description:
* erform a modular reduction. R = A mod B
*
* Input Parameters:
* R - The destination MPI for the residue value
* A - The MPI to compute the residue of
* B - The base of the modular reduction
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_mod_mpi(struct esp32c3_mpi_s *R,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
DEBUGASSERT(R != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
if (esp32c3_mpi_cmp_int(B, 0) < 0)
{
return ESP32C3_ERR_MPI_NEGATIVE_VALUE;
}
ESP32C3_MPI_CHK(esp32c3_mpi_div_mpi(NULL, R, A, B), cleanup);
while (esp32c3_mpi_cmp_int(R, 0) < 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(R, R, B), cleanup);
}
while (esp32c3_mpi_cmp_mpi(R, B) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(R, R, B), cleanup);
}
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_mod_int
*
* Description:
* Perform a modular reduction with respect to an integer: r = A mod b
*
* Input Parameters:
* r - The address at which to store the residue
* A - The MPI to compute the residue of
* b - The integer base of the modular reduction
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_mod_int(uint32_t *r,
const struct esp32c3_mpi_s *A, int32_t b)
{
size_t i;
uint32_t x;
uint32_t y;
uint32_t z;
DEBUGASSERT(r != NULL);
DEBUGASSERT(A != NULL);
if (b == 0)
{
return ESP32C3_ERR_MPI_DIVISION_BY_ZERO;
}
if (b < 0)
{
return ESP32C3_ERR_MPI_NEGATIVE_VALUE;
}
/* handle trivial cases */
if (b == 1)
{
*r = 0;
return OK;
}
if (b == 2)
{
*r = A->p[0] & 1;
return OK;
}
/* general case */
for (i = A->n, y = 0; i > 0; i--)
{
x = A->p[i - 1];
y = (y << BIH) | (x >> BIH);
z = y / b;
y -= z * b;
x <<= BIH;
y = (y << BIH) | (x >> BIH);
z = y / b;
y -= z * b;
}
/* If A is negative, then the current y represents a negative value.
* Flipping it to the positive side.
*/
if (A->s < 0 && y != 0)
{
y = b - y;
}
*r = y;
return OK;
}
/****************************************************************************
* Name: esp32c3_mpi_exp_mod
*
* Description:
* Perform a sliding-window exponentiation: X = A^E mod N
*
* Input Parameters:
* X - The destination MPI
* A - The base of the exponentiation
* E - The exponent MPI
* N - The base for the modular reduction
* _RR - A helper MPI depending solely on \p N which can be used to
* speed-up multiple modular exponentiations for the same value
* of \p N.
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_exp_mod(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *E,
const struct esp32c3_mpi_s *N,
struct esp32c3_mpi_s *_RR)
{
int ret;
size_t wbits;
size_t wsize;
size_t one = 1;
size_t i;
size_t j;
size_t nblimbs;
size_t bufsize;
size_t nbits;
uint32_t ei;
uint32_t mm;
uint32_t state;
struct esp32c3_mpi_s RR;
struct esp32c3_mpi_s T;
struct esp32c3_mpi_s W[1 << ESP32C3_MPI_WINDOW_SIZE];
struct esp32c3_mpi_s apos;
int neg;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(E != NULL);
DEBUGASSERT(N != NULL);
if (esp32c3_mpi_cmp_int(N, 0) <= 0 || (N->p[0] & 1) == 0)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
if (esp32c3_mpi_cmp_int(E, 0) < 0)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
if (esp32c3_mpi_bitlen(E) > ESP32C3_MPI_MAX_BITS ||
esp32c3_mpi_bitlen(N) > ESP32C3_MPI_MAX_BITS)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
/* Init temps and window size
*/
mpi_montg_init(&mm, N);
esp32c3_mpi_init(&RR); esp32c3_mpi_init(&T);
esp32c3_mpi_init(&apos);
memset(W, 0, sizeof(W));
i = esp32c3_mpi_bitlen(E);
wsize = (i > 671) ? 6 : (i > 239) ? 5 :
(i > 79) ? 4 : (i > 23) ? 3 : 1;
#if (ESP32C3_MPI_WINDOW_SIZE < 6)
if (wsize > ESP32C3_MPI_WINDOW_SIZE)
{
wsize = ESP32C3_MPI_WINDOW_SIZE;
}
#endif
j = N->n + 1;
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, j), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&W[1], j), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&T, j * 2), cleanup);
/* Compensate for negative A (and correct at the end) */
neg = (A->s == -1);
if (neg)
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&apos, A), cleanup);
apos.s = 1;
A = &apos;
}
/* If 1st call, pre-compute R^2 mod N */
if (_RR == NULL || _RR->p == NULL)
{
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&RR, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&RR, N->n * 2 * BIL), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&RR, &RR, N), cleanup);
if (_RR != NULL)
{
memcpy(_RR, &RR, sizeof(struct esp32c3_mpi_s));
}
}
else
{
memcpy(&RR, _RR, sizeof(struct esp32c3_mpi_s));
}
/* W[1] = A * R^2 * R^-1 mod N = A * R mod N */
if (esp32c3_mpi_cmp_mpi(A, N) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&W[1], A, N), cleanup);
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&W[1], A), cleanup);
}
mpi_montmul(&W[1], &RR, N, mm, &T);
/* X = R^2 * R^-1 mod N = R mod N */
ESP32C3_MPI_CHK(esp32c3_mpi_copy(X, &RR), cleanup);
mpi_montred(X, N, mm, &T);
if (wsize > 1)
{
/* W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) */
j = one << (wsize - 1);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&W[j], N->n + 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&W[j], &W[1]), cleanup);
for (i = 0; i < wsize - 1; i++)
{
mpi_montmul(&W[j], &W[j], N, mm, &T);
}
/* W[i] = W[i - 1] * W[1] */
for (i = j + 1; i < (one << wsize); i++)
{
ESP32C3_MPI_CHK(esp32c3_mpi_grow(&W[i], N->n + 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&W[i], &W[i - 1]), cleanup);
mpi_montmul(&W[i], &W[1], N, mm, &T);
}
}
nblimbs = E->n;
bufsize = 0;
nbits = 0;
wbits = 0;
state = 0;
while (1)
{
if (bufsize == 0)
{
if (nblimbs == 0)
{
break;
}
nblimbs--;
bufsize = sizeof(uint32_t) << 3;
}
bufsize--;
ei = (E->p[nblimbs] >> bufsize) & 1;
/* skip leading 0s */
if (ei == 0 && state == 0)
{
continue;
}
if (ei == 0 && state == 1)
{
/* out of window, square X */
mpi_montmul(X, X, N, mm, &T);
continue;
}
/* add ei to current window */
state = 2;
nbits++;
wbits |= (ei << (wsize - nbits));
if (nbits == wsize)
{
/* X = X^wsize R^-1 mod N */
for (i = 0; i < wsize; i++)
{
mpi_montmul(X, X, N, mm, &T);
}
/* X = X * W[wbits] R^-1 mod N */
mpi_montmul(X, &W[wbits], N, mm, &T);
state--;
nbits = 0;
wbits = 0;
}
}
/* process the remaining bits */
for (i = 0; i < nbits; i++)
{
mpi_montmul(X, X, N, mm, &T);
wbits <<= 1;
if ((wbits & (one << wsize)) != 0)
mpi_montmul(X, &W[1], N, mm, &T);
}
/* X = A^E * R * R^-1 mod N = A^E mod N */
mpi_montred(X, N, mm, &T);
if (neg && E->n != 0 && (E->p[0] & 1) != 0)
{
X->s = -1;
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(X, N, X), cleanup);
}
cleanup:
for (i = (one << (wsize - 1)); i < (one << wsize); i++)
{
esp32c3_mpi_free(&W[i]);
}
esp32c3_mpi_free(&W[1]);
esp32c3_mpi_free(&T);
esp32c3_mpi_free(&apos);
if (_RR == NULL || _RR->p == NULL)
{
esp32c3_mpi_free(&RR);
}
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_gcd
*
* Description:
* Compute the greatest common divisor: G = gcd(A, B)
*
* Input Parameters:
* G - The destination MPI
* A - The first operand
* B - The second operand
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_gcd(struct esp32c3_mpi_s *G,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *B)
{
int ret;
size_t lz;
size_t lzt;
struct esp32c3_mpi_s TG;
struct esp32c3_mpi_s TA;
struct esp32c3_mpi_s TB;
DEBUGASSERT(G != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(B != NULL);
esp32c3_mpi_init(&TG); esp32c3_mpi_init(&TA); esp32c3_mpi_init(&TB);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TA, A), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TB, B), cleanup);
lz = esp32c3_mpi_lsb(&TA);
lzt = esp32c3_mpi_lsb(&TB);
if (lzt < lz)
{
lz = lzt;
}
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TA, lz), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TB, lz), cleanup);
TA.s = TB.s = 1;
while (esp32c3_mpi_cmp_int(&TA, 0) != 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TA, esp32c3_mpi_lsb(&TA)),
cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TB, esp32c3_mpi_lsb(&TB)),
cleanup);
if (esp32c3_mpi_cmp_mpi(&TA, &TB) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(&TA, &TA, &TB), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TA, 1), cleanup);
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_abs(&TB, &TB, &TA), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TB, 1), cleanup);
}
}
ESP32C3_MPI_CHK(esp32c3_mpi_shift_l(&TB, lz), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(G, &TB), cleanup);
cleanup:
esp32c3_mpi_free(&TG); esp32c3_mpi_free(&TA); esp32c3_mpi_free(&TB);
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_fill_random
*
* Description:
* Fill an MPI with a number of random bytes
*
* Input Parameters:
* X - The destination MPI
* size - The number of random bytes to generate
* f_rng - The RNG function to use. This must not be \c NULL
* p_rng - The RNG parameter to be passed to \p f_rng
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_fill_random(struct esp32c3_mpi_s *X, size_t size,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
int ret;
size_t const limbs = CHARS_TO_LIMBS(size);
size_t const overhead = (limbs * CIL) - size;
unsigned char *XP;
DEBUGASSERT(X != NULL);
DEBUGASSERT(f_rng != NULL);
/* Ensure that target MPI has exactly the necessary number of limbs */
if (X->n != limbs)
{
esp32c3_mpi_free(X);
esp32c3_mpi_init(X);
ESP32C3_MPI_CHK(esp32c3_mpi_grow(X, limbs), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_lset(X, 0), cleanup);
XP = (unsigned char *) X->p;
ESP32C3_MPI_CHK(f_rng(p_rng, XP + overhead, size), cleanup);
mpi_bigendian_to_host(X->p, limbs);
cleanup:
return ret;
}
/****************************************************************************
* Name: esp32c3_mpi_inv_mod
*
* Description:
* Compute the modular inverse: X = A^-1 mod N
*
* Input Parameters:
* X - The destination MPI
* A - The MPI to calculate the modular inverse of
* N - The base of the modular inversion
*
* Returned Value:
* OK on success; Negated errno on failure.
*
****************************************************************************/
int esp32c3_mpi_inv_mod(struct esp32c3_mpi_s *X,
const struct esp32c3_mpi_s *A,
const struct esp32c3_mpi_s *N)
{
int ret;
struct esp32c3_mpi_s G;
struct esp32c3_mpi_s TA;
struct esp32c3_mpi_s TU;
struct esp32c3_mpi_s U1;
struct esp32c3_mpi_s U2;
struct esp32c3_mpi_s TB;
struct esp32c3_mpi_s TV;
struct esp32c3_mpi_s V1;
struct esp32c3_mpi_s V2;
DEBUGASSERT(X != NULL);
DEBUGASSERT(A != NULL);
DEBUGASSERT(N != NULL);
if (esp32c3_mpi_cmp_int(N, 1) <= 0)
{
return ESP32C3_ERR_MPI_BAD_INPUT_DATA;
}
esp32c3_mpi_init(&TA);
esp32c3_mpi_init(&TU);
esp32c3_mpi_init(&U1);
esp32c3_mpi_init(&U2);
esp32c3_mpi_init(&G);
esp32c3_mpi_init(&TB);
esp32c3_mpi_init(&TV);
esp32c3_mpi_init(&V1);
esp32c3_mpi_init(&V2);
ESP32C3_MPI_CHK(esp32c3_mpi_gcd(&G, A, N), cleanup);
if (esp32c3_mpi_cmp_int(&G, 1) != 0)
{
ret = ESP32C3_ERR_MPI_NOT_ACCEPTABLE;
goto cleanup;
}
ESP32C3_MPI_CHK(esp32c3_mpi_mod_mpi(&TA, A, N), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TU, &TA), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TB, N), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_copy(&TV, N), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&U1, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&U2, 0), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&V1, 0), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_lset(&V2, 1), cleanup);
do
{
while ((TU.p[0] & 1) == 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TU, 1), cleanup);
if ((U1.p[0] & 1) != 0 || (U2.p[0] & 1) != 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&U1, &U1, &TB), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&U2, &U2, &TA), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&U1, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&U2, 1), cleanup);
}
while ((TV.p[0] & 1) == 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&TV, 1), cleanup);
if ((V1.p[0] & 1) != 0 || (V2.p[0] & 1) != 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&V1, &V1, &TB), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&V2, &V2, &TA), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&V1, 1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_shift_r(&V2, 1), cleanup);
}
if (esp32c3_mpi_cmp_mpi(&TU, &TV) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&TU, &TU, &TV), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&U1, &U1, &V1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&U2, &U2, &V2), cleanup);
}
else
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&TV, &TV, &TU), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&V1, &V1, &U1), cleanup);
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&V2, &V2, &U2), cleanup);
}
}
while (esp32c3_mpi_cmp_int(&TU, 0) != 0);
while (esp32c3_mpi_cmp_int(&V1, 0) < 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_add_mpi(&V1, &V1, N), cleanup);
}
while (esp32c3_mpi_cmp_mpi(&V1, N) >= 0)
{
ESP32C3_MPI_CHK(esp32c3_mpi_sub_mpi(&V1, &V1, N), cleanup);
}
ESP32C3_MPI_CHK(esp32c3_mpi_copy(X, &V1), cleanup);
cleanup:
esp32c3_mpi_free(&TA);
esp32c3_mpi_free(&TU);
esp32c3_mpi_free(&U1);
esp32c3_mpi_free(&U2);
esp32c3_mpi_free(&G);
esp32c3_mpi_free(&TB);
esp32c3_mpi_free(&TV);
esp32c3_mpi_free(&V1);
esp32c3_mpi_free(&V2);
return ret;
}
#endif /* CONFIG_ESP32C3_BIGNUM_ACCELERATOR */