// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2014, STMicroelectronics International N.V. */ #include "mpa.h" /************************************************************* * * HELPERS * *************************************************************/ /*------------------------------------------------------------ * * These functions have ARM assembler implementations * */ #if !defined(USE_ARM_ASM) /* -------------------------------------------------------------------- * Function: __mpa_mul_add_word * * Multiplies a and b and adds the incoming carry to produce the product p * outgoing carry is stored in *carry. */ void __mpa_mul_add_word(mpa_word_t a, mpa_word_t b, mpa_word_t *p, mpa_word_t *carry) { #if defined(MPA_SUPPORT_DWORD_T) mpa_dword_t prod; prod = (mpa_dword_t) (a) * (mpa_dword_t) (b) + (mpa_dword_t) (*carry); *p = (mpa_word_t) prod; *carry = (mpa_word_t) (prod >> MPA_WORD_SIZE); #else #error "error, write non-dword_t code for __mpa_mul_add_word" #endif } /* -------------------------------------------------------------------- * Function: __mpa_mul_add_word_cum * * Multiplies a and b and adds the incoming carry and the cumulative * product stored in *p. * Outgoing carry is stored in *carry. */ void __mpa_mul_add_word_cum(mpa_word_t a, mpa_word_t b, mpa_word_t *p, mpa_word_t *carry) { #if defined(MPA_SUPPORT_DWORD_T) mpa_dword_t prod; prod = (mpa_dword_t) (a) * (mpa_dword_t) (b) + (mpa_dword_t) (*p) + (mpa_dword_t) (*carry); *p = (mpa_word_t) prod; *carry = (mpa_word_t) (prod >> MPA_WORD_SIZE); #else #error "error: write non-dword_t code for __mpa_mul_add_word_cum" #endif } #endif /* USE_ARM_ASM */ /* -------------------------------------------------------------------- * Function: __mpa_abs_mul_word * * Simpler multiplication when one operand is known to be a word. * Calculates |op1| * op2, op2 is always positive (larger than zero). * Dest needs to be distinct from op1. */ void __mpa_abs_mul_word(mpanum dest, const mpanum op1, mpa_word_t op2) { mpa_word_t i; mpa_word_t carry; mpa_word_t *prod; const mpa_word_t *a; /* clear dest digits */ mpa_memset(dest->d, 0, dest->alloc * BYTES_PER_WORD); a = op1->d; prod = dest->d; carry = 0; for (i = 0; i < __mpanum_size(op1); i++) { __mpa_mul_add_word(*a, op2, prod + i, &carry); a++; } dest->size = i; if (carry) { *(prod + i) = carry; dest->size++; } } /* -------------------------------------------------------------------- * Function: __mpa_abs_mul * * Calculates |op1| * |op2| and puts result in dest. * dest must be big enough to hold result and cannot be * the same as op1 or op2. */ void __mpa_abs_mul(mpanum dest, const mpanum op1, const mpanum op2) { mpa_word_t i = 0; mpa_word_t j = 0; mpa_word_t carry = 0; mpa_word_t *prod; const mpa_word_t *a; const mpa_word_t *b; /* clear dest digits */ mpa_memset(dest->d, 0, dest->alloc * BYTES_PER_WORD); a = op1->d; prod = dest->d; for (i = 0; i < __mpanum_size(op1); i++) { b = op2->d; carry = 0; for (j = 0; j < __mpanum_size(op2); j++) { __mpa_mul_add_word_cum(*a, *b, prod + j, &carry); b++; } if (carry) *(prod + j) = carry; a++; prod++; } dest->size = i + j - 1; if (carry) dest->size++; } /************************************************************* * * LIB FUNCTIONS * *************************************************************/ /* -------------------------------------------------------------------- * Function: mpa_mul * * dest = op1 * op2 */ void mpa_mul(mpanum dest, const mpanum op1, const mpanum op2, mpa_scratch_mem pool) { mpanum tmp_dest; char mem_marker; if (__mpanum_is_zero(op1) || __mpanum_is_zero(op2)) { mpa_set_word(dest, 0); return; } /* handle the case when dest is one of the operands */ mem_marker = (dest == op1 || dest == op2); if (mem_marker) mpa_alloc_static_temp_var(&tmp_dest, pool); else tmp_dest = dest; __mpa_abs_mul(tmp_dest, op1, op2); if (__mpanum_sign(op1) != __mpanum_sign(op2)) __mpanum_neg(tmp_dest); mpa_copy(dest, tmp_dest); if (mem_marker) mpa_free_static_temp_var(&tmp_dest, pool); } /* -------------------------------------------------------------------- * Function: mpa_mul_word * * Calculates op1 * op2, where op2 is a word, puts result in dest. */ void mpa_mul_word(mpanum dest, const mpanum op1, mpa_word_t op2, mpa_scratch_mem pool) { int sign_1; mpanum tmp_dest; char mem_marker; if (__mpanum_is_zero(op1) || op2 == 0) { mpa_set_word(dest, 0); return; } sign_1 = __mpanum_sign(op1); /* handle the case when dest is the operand */ mem_marker = (dest == op1); if (mem_marker) mpa_alloc_static_temp_var(&tmp_dest, pool); else tmp_dest = dest; __mpa_abs_mul_word(tmp_dest, op1, op2); if (sign_1 == MPA_NEG_SIGN) __mpanum_neg(tmp_dest); mpa_copy(dest, tmp_dest); if (mem_marker) mpa_free_static_temp_var(&tmp_dest, pool); }