summaryrefslogtreecommitdiff
path: root/lib/libmpa/mpa_mul.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libmpa/mpa_mul.c')
-rw-r--r--lib/libmpa/mpa_mul.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/lib/libmpa/mpa_mul.c b/lib/libmpa/mpa_mul.c
new file mode 100644
index 0000000..4875f08
--- /dev/null
+++ b/lib/libmpa/mpa_mul.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#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);
+}