summaryrefslogtreecommitdiff
path: root/lib/libmpa
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libmpa')
-rw-r--r--lib/libmpa/arch/arm/mpa_a32.S428
-rw-r--r--lib/libmpa/arch/arm/sub.mk0
-rw-r--r--lib/libmpa/include/mpa.h238
-rw-r--r--lib/libmpa/include/mpalib.h432
-rw-r--r--lib/libmpa/include/mpalib_config.h125
-rw-r--r--lib/libmpa/mpa_addsub.c561
-rw-r--r--lib/libmpa/mpa_cmp.c171
-rw-r--r--lib/libmpa/mpa_conv.c92
-rw-r--r--lib/libmpa/mpa_div.c413
-rw-r--r--lib/libmpa/mpa_expmod.c85
-rw-r--r--lib/libmpa/mpa_gcd.c372
-rw-r--r--lib/libmpa/mpa_init.c69
-rw-r--r--lib/libmpa/mpa_io.c538
-rw-r--r--lib/libmpa/mpa_mem_static.c177
-rw-r--r--lib/libmpa/mpa_misc.c189
-rw-r--r--lib/libmpa/mpa_modulus.c144
-rw-r--r--lib/libmpa/mpa_montgomery.c266
-rw-r--r--lib/libmpa/mpa_mul.c228
-rw-r--r--lib/libmpa/mpa_primetable.h242
-rw-r--r--lib/libmpa/mpa_primetest.c291
-rw-r--r--lib/libmpa/mpa_random.c81
-rw-r--r--lib/libmpa/mpa_shift.c237
-rw-r--r--lib/libmpa/sub.mk45
23 files changed, 5424 insertions, 0 deletions
diff --git a/lib/libmpa/arch/arm/mpa_a32.S b/lib/libmpa/arch/arm/mpa_a32.S
new file mode 100644
index 0000000..590de2b
--- /dev/null
+++ b/lib/libmpa/arch/arm/mpa_a32.S
@@ -0,0 +1,428 @@
+/*
+ * 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.
+ */
+ .syntax unified
+ .thumb
+ .section .text
+ .align 2
+
+ .global __mpa_full_adder
+ .global __mpa_full_sub
+ .global __mpa_full_adder_ackum
+ .global __mpa_div_dword
+ .global __mpa_mul_add_word
+ .global __mpa_mul_add_word_cum
+ .global __mpa_montgomery_mul_add
+ .global __mpa_montgomery_sub_ack
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_full_adder
+@
+@ A word_t sized full adder. Incoming carry is in *carry.
+@ The sum will be put in *sum and the
+@ outgoing carry will be returned in *carry
+@
+@ void __mpa_full_adder( mpa_word_t a,
+@ mpa_word_t b,
+@ mpa_word_t* sum,
+@ mpa_word_t* carry)
+@
+ .thumb_func
+ .type __mpa_full_adder, %function
+__mpa_full_adder:
+ push {r9}
+ ldr r9, [r3] @ r9 holds incoming carry
+ adds r1, r1, r0 @ r1 holds b + a
+ mov r12, #0 @
+ adc r0, r12, #0 @ r0 holds carry of a + b
+ adds r1, r1, r9 @ r1 holds a + b + incoming carry
+ str r1, [r2] @ *sum <- r1
+ adc r0, r0, #0 @ r0 holds acc carry
+ str r0, [r3] @ *carry <- r0
+ pop {r9}
+ bx lr
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_full_sub
+@
+@ A word_t sized full subtraction function. Incoming carry is in *carry
+@ The difference will be put in *diff and the outgoing carry will be returned
+@ in *carry
+@
+@ void __mpa_full_sub(mpa_word_t a,
+@ mpa_word_t b,
+@ mpa_word_t* diff,
+@ mpa_word_t* carry);
+@
+ .thumb_func
+ .type __mpa_full_sub, %function
+__mpa_full_sub:
+ push {r9}
+ ldr r9, [r3] @ r9 holds incomming carry
+ subs r1, r0, r1 @ r1 holds a - b
+ mov r12, #0
+ sbc r0, r12, #0 @ r0 holds carry
+ subs r1, r1, r9 @ r1 holds a - b - carry
+ str r1, [r2] @ *diff <- r1
+ sbc r0, r0, #0 @ r0 <- r0 - carry
+ rsbs r0, r0, #0 @ r0 <- 0 - r0 outgoing carry
+ str r0, [r3] @ *carry <- r0
+ pop {r9}
+ bx lr
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_full_adder_ackum
+@
+@ A word_t sized full adder with ackumulate. *d = *d + e + *carry
+@ Outgoing carry is in *carry
+@
+@ void __mpa_full_adder_ackum( mpa_word_t* d,
+@ mpa_word_t e,
+@ mpa_word_t* carry)
+@
+ .thumb_func
+ .type __mpa_full_adder_ackum, %function
+__mpa_full_adder_ackum:
+ push {r9}
+ ldr r12, [r0] @ r12 <- *d
+ mov r9, #0 @
+ ldr r3, [r2] @ r3 holds incoming carry
+ adds r1, r1, r12 @ r1 <- e + *d
+ adc r9, r9, #0 @ r9 <- carry
+ adds r1, r1, r3 @ r1 <- r1 + *carry
+ str r1, [r0] @ *d <- sum
+ adc r0, r9, #0 @ r0 <- outgoing carry
+ str r0, [r2] @ *carry <- carry
+ pop {r9}
+ bx lr
+
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_div_dword
+@
+@ Wrapper for the soft div. Calculates quotient and remainder of
+@ ((x1 << WORD_SIZE) + x0 ) / y
+@
+@ mpa_word_t __mpa_div_dword(mpa_word_t x0,
+@ mpa_word_t x1,
+@ mpa_word_t y,
+@ mpa_word_t* rem)
+@
+@ returns the quotient in r0 and the remainder in *rem
+@
+@ At entrace
+@ r0 low32 of num
+@ r1 high32 of num
+@ r2 y (becomes high32 of den)
+@ r3 addr of rem
+ .thumb_func
+ .type __mpa_div_dword, %function
+__mpa_div_dword:
+ push {r4, r5, r6, r7, r8, r9, lr}@
+
+ mov r12, #0 @ r12 holds low32 of den
+ @ r2 holds high32 of den
+ mov lr, #1 @ lr holds high32 of qbit
+ movs r4, #0 @ r4 holds low32 of qbit
+ cmp r2, #-1 @ if den >= 0
+ bgt normalize @ branch to normalize
+ mov r9, #0 @ r9 holds low of quot
+ mov r8, #0 @ r8 holds high of quot
+
+soft_div_main:
+ cmp r12, r0 @ cmp low(den) low(num)
+ mov r6, #0 @
+ it hi @
+ movhi r6, #1 @ r6 is 1 if low(den) > low(num)
+ cmp r2, r1 @ cmp high(den) high(num)
+ mov r5, #0 @
+ it hi @
+ movhi r5, #1 @ r5 if 1 if high(den) > high(num)
+ it eq @
+ moveq r5, r6 @ if high is equal let low decide
+ cbnz r5, shift_right @ if r5 == 1 branch
+
+ adds r9, r9, r4 @ quot += qbit
+ adc r8, r8, lr @
+ subs r0, r0, r12 @ num -= den
+ sbcs r1, r2 @
+
+shift_right:
+@
+@ These right shifts should be done as
+@
+@ lsrs r2, r2, #1 @ right shift den >>= 1
+@ rrx r12, r12
+@ lsrs lr, lr, #1 @ right shift qbit >>= 1
+@ rrx r4, r4
+@
+@ but due to a compiler error in the STE toolchain (2012-05-03)
+@ we must implement this as:
+
+ and r7, r2, #1
+ mov r2, r2, lsr #1
+ mov r7, r7, lsl #31
+ mov r12, r12, lsr #1
+ orr r12, r12, r7
+
+ and r7, lr, #1
+ mov lr, lr, lsr #1
+ mov r7, r7, lsl #31
+ mov r4, r4, lsr #1
+ orr r4, r4, r7
+
+@
+@ end of compiler bug fix
+@
+ orrs r5, r4, lr @ while qbit != 0
+ bne soft_div_main @ do mainloop
+
+store_and_exit:
+ cmp r3, #0 @ if (r != NULL)
+ it ne @
+ strne r0, [r3] @ store remainder into *r
+ mov r0, r9 @
+ pop {r4, r5, r6, r7, r8, r9, pc}@ clean up and exit
+
+normalize:
+ adds r4, r4, r4 @ qbit <<= 1
+ adc lr, lr, lr @
+ adds r12, r12, r12 @ den <<= 1
+ adcs r2, r2 @
+ cmp r2, #-1 @ while den >= 0
+ bgt normalize @ do normalize
+
+ mov r9, #0 @
+ orrs r6, r4, lr @ if qbit == 0
+ beq store_and_exit @ done, branch to store r and exit
+
+ mov r8, r9 @ set quot = 0 (r9 = 0 r8 = 0)
+ b soft_div_main @ and branch to main loop
+
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_mul_add_word
+@
+@ Multiplies a and b and adds the incoming carry tp produce the product.
+@ 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)
+@
+@
+ .thumb_func
+ .type __mpa_mul_add_word, %function
+__mpa_mul_add_word:
+ push {r9}
+ umull r1, r9, r1, r0 @ r1, r9 <- a * b
+ ldr r0, [r3] @ r0 <- incoming carry
+ adds r1, r1, r0 @ add incoming carry to product
+ str r1, [r2] @ store low32 of product
+ adc r0, r9, #0 @ add carry to high32
+ str r0, [r3] @ store outgoing carry
+ pop {r9}
+ bx lr
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_mul_add_word_cum
+@
+@ Multiplies a and b and adds the incoming carry and the cumulative
+@ product.
+@ 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)
+@
+@
+ .thumb_func
+ .type __mpa_mul_add_word_cum, %function
+__mpa_mul_add_word_cum:
+ push {r9}
+ umull r12, r9, r1, r0 @ r9, r12 <- a * b
+ ldr r0, [r2] @ r0 holds incoming product
+ ldr r1, [r3] @ r1 holds incoming carry
+ adds r0, r0, r12 @ r0 holds incoming product + new low32
+ adc r9, r9, #0 @ add carry to high32
+ adds r0, r0, r1 @ add incoming carry
+ str r0, [r2] @ store outgoing product
+ adc r0, r9, #0 @ store outgoing carry in r0
+ str r0, [r3] @ and write to [r3]
+ pop {r9}
+ bx lr
+
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_montgomery_mul_add
+@
+@ Calculates dest = dest + src * w
+@ Dest must be big enough to hold the result
+@
+@ void __mpa_montgomery_mul_add(mpanum dest,
+@ mpanum src,
+@ mpa_word_t w)
+@
+ .thumb_func
+ .type __mpa_montgomery_mul_add, %function
+__mpa_montgomery_mul_add:
+ push {r4, r5, r6, r7, lr}
+ add r7, sp, #12
+ push {r8, r9, r10, r11}
+ cbz r2, mm_mul_add_exit @ if w == 0 return
+ ldr r3, [r1, #4] @ r3 holds src->size
+ add r9, r0, #8 @ r9 holds &dest->d (dest_begin)
+ cmp r3, #1 @
+ mov r3, r9 @ r3 holds &dest->d (ddig)
+ blt mm_mul_add_check_size @ if src->size == NULL jump
+ add r12, r1, #8 @ r12 holds &src->d
+ mov lr, #0 @
+ movs r3, #0 @
+ movs r4, #0 @ r4 holds carry
+ movs r5, #0 @ r5 holds inx
+
+mm_main_loop:
+ ldr r6, [r12, r5, lsl #2] @ r6 holds src->d[idx]
+ adds r3, #4
+ ldr r11, [r9, r5, lsl #2] @ r11 holds dest->d[idx]
+ umull r10, r8, r6, r2 @ r8, r10 holds src->d[idx] * w
+ mla r8, r6, lr, r8 @ r8 <- r6*0 + r8 ??
+ adds r6, r11, r4 @ r6 <- dest->d[idx] + carry
+ adc r4, lr, #0 @ r4 holds C
+ adds r6, r6, r10 @ r6 holds low32 of result
+ str r6, [r9, r5, lsl #2] @ store into dest->d[idx]
+ add r5, r5, #1 @ idx++
+ ldr r6, [r1, #4] @ r6 holds src->size
+ adc r4, r4, r8 @ r4 holds high32 of result
+ cmp r5, r6 @ while (idx < src->size)
+ blt mm_main_loop @ do jump
+
+ adds r1, r0, r3 @
+ cmp r4, #0 @ check carry
+ add r3, r1, #8 @ r3 holds &dest->d[idx]
+ beq mm_mul_add_check_size @ jump if no carry
+ movs r1, #0
+
+mm_carry_loop:
+ ldr r2, [r3] @ r2 holds dest->d[idx]
+ adds r2, r2, r4 @ r2 <- r2 + carry
+ str r2, [r3], #4 @ store at dest->d[idx++]
+ adcs r4, r1, #0 @ r4 holds new C
+ bne mm_carry_loop @ if r4 != 0 jump
+
+mm_mul_add_check_size:
+ sub r1, r3, r9 @ r1 holds ddig - dest_begin
+ ldr r2, [r0, #4] @ r2 holds dest->size
+ asrs r1, r1, #2 @ mult by 2 to go from byte addr to word
+ cmp r1, r2 @
+ it gt @
+ strgt r1, [r0, #4] @ store new size if idx > dest->size
+
+mm_mul_add_exit:
+ pop {r8, r9, r10, r11}
+ pop {r4, r5, r6, r7, pc}
+
+
+@ --------------------------------------------------------------------
+@ Function: __mpa_montgomery_sub_ack
+@ Calculates dest = dest - src
+@ Assumption: dest >= src and both non-negative
+@ and dest > src.
+@
+@
+@ void __mpa_montgomery_sub_ack(mpanum dest,
+@ mpanum src)
+@
+ .thumb_func
+ .type __mpa_montgomery_sub_ack, %function
+__mpa_montgomery_sub_ack:
+ push {r4, r5, r7, r9, lr}
+ ldr r2, [r1, #4]
+ add r9, r0, #8
+ mov lr, #0
+ add r7, sp, #8
+ cmp r2, #0
+ bgt LBB1_10
+ movs r2, #0
+ b LBB1_6
+LBB1_2:
+ cbz r4, LBB1_6
+ movs r1, #0
+ LBB1_4:
+ add r5, r0, r2, lsl #2
+ adds r3, #4
+ adds r2, #1
+ ldr r4, [r5, #8]
+ subs r4, r4, r12
+ str r4, [r5, #8]
+ sbcs r5, r1, #0
+ rsb r12, r5, #0
+ bne LBB1_4
+ add r9, r0, r3
+LBB1_6:
+ ldr r3, [r0, #4]
+ cmp r2, r3
+ blt LBB1_12
+ sub r1, r9, #4
+ subs r2, r3, #1
+LBB1_8:
+ adds r3, r2, #1
+ cmp r3, #1
+ blt LBB1_12
+ ldr r3, [r1]
+ cmp r3, #0
+ it ne
+ popne {r4, r5, r7, r9, pc}
+ str r2, [r0, #4]
+ subs r2, #1
+ subs r1, #4
+ b LBB1_8
+LBB1_10:
+ movs r3, #8
+ movs r2, #0
+ mov r12, #0
+LBB1_11:
+ add r5, r1, r2, lsl #2
+ ldr r4, [r9]
+ adds r3, #4
+ adds r2, #1
+ ldr r5, [r5, #8]
+ subs r5, r4, r5
+ sbc r4, lr, #0
+ subs r5, r5, r12
+ str r5, [r9], #4
+ sbc r4, r4, #0
+ ldr r5, [r1, #4]
+ rsb r12, r4, #0
+ cmp r2, r5
+ blt LBB1_11
+ b LBB1_2
+LBB1_12:
+ pop {r4, r5, r7, r9, pc}
+
+
diff --git a/lib/libmpa/arch/arm/sub.mk b/lib/libmpa/arch/arm/sub.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/libmpa/arch/arm/sub.mk
diff --git a/lib/libmpa/include/mpa.h b/lib/libmpa/include/mpa.h
new file mode 100644
index 0000000..c5aa5de
--- /dev/null
+++ b/lib/libmpa/include/mpa.h
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+#ifndef GUARD_MPA_H
+#define GUARD_MPA_H
+
+#include "mpalib.h"
+
+/************************************************************************\
+ * MACRO DEFINITIONS
+\************************************************************************/
+
+#define WORD_SIZE MPA_WORD_SIZE
+#define BYTES_PER_WORD (MPA_WORD_SIZE >> 3)
+#define NIBBLES_PER_WORD (MPA_WORD_SIZE >> 2)
+#define LOG_OF_WORD_SIZE MPA_LOG_OF_WORD_SIZE
+#define LOG_OF_BYTES_PER_WORD MPA_LOG_OF_BYTES_PER_WORD
+#define WORD_ALL_BITS_ONE ((mpa_word_t)-1)
+
+/* number of bytes to hold x bits, x must be positive integer */
+#define BITS_TO_BYTES(x) (((x)+7) >> 3)
+/* convert from bytes to bits */
+#define BYTES_TO_BITS(x) ((x) << 3)
+
+/* convert from words to bytes */
+#define WORDS_TO_BYTES(x) ((x) << LOG_OF_BYTES_PER_WORD)
+/* convert from bytes to minimum number of words needed to hold x bytes */
+#define BYTES_TO_WORDS(x) (((x) + BYTES_PER_WORD - 1) >> LOG_OF_BYTES_PER_WORD)
+
+/* convert from bits to words and vice versa */
+#define WORDS_TO_BITS(x) ((x) * MPA_WORD_SIZE)
+#define BITS_TO_WORDS(x) (((x) + MPA_WORD_SIZE - 1) / MPA_WORD_SIZE)
+
+#define __MAX(a, b) ((a) < (b) ? (b) : (a))
+#define __MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/* macros to access internal variables in a mpa_numbase */
+
+#define MPA_NEG_SIGN -1
+#define MPA_POS_SIGN 1
+
+#define __mpanum_alloced(x) ((x)->alloc)
+#define __mpanum_size(x) ((mpa_usize_t)((x)->size >= 0 ? \
+ (x)->size : -(x)->size))
+#define __mpanum_sign(x) ((x)->size >= 0 ? MPA_POS_SIGN : MPA_NEG_SIGN)
+
+/* macros to set internal variables in mpa_numbase */
+
+/* SetSign take either MPA_POS_SIGN or MPA_NEG_SIGN as argument */
+#define __mpanum_set_sign(x, s) \
+ do { \
+ if (__mpanum_sign(x) != (s)) \
+ (x)->size = -(x)->size; \
+ } while (0)
+#define __mpanum_is_zero(x) ((x)->size == 0)
+#define __mpanum_neg(x) ((x)->size = -((x)->size))
+
+/* Get most significant word of x, call only on non-zero x */
+#define __mpanum_msw(x) ((x)->d[__mpanum_size(x)-1])
+#define __mpanum_lsw(x) ((x)->d[0])
+
+/* Get word idx of x, if idx >= size, return 0
+ * This macro is used in the montgomery multiplication to allow
+ * operands to have shorter alloc than n
+ */
+#define __mpanum_get_word(idx, x) ((idx >= __mpanum_size(x)) ? \
+ 0 : ((x)->d[idx]))
+
+/* n = 0..NIBBLES_PER_WORD-1 */
+#if defined(MPA_LITTLE_ENDIAN)
+#define NIBBLE_OF_WORD(n, w) (((w) >> ((n) << 2)) & 0xf)
+#elif defined(MPA_BIG_ENDIAN)
+#define NIBBLE_OF_WORD(n, w) (((w) >> ((7-(n)) << 2)) & 0xf)
+#else
+#error "You must define either MPA_LITTLE_ENDIAN or MPA_BIG_ENDIAN, see mpalib_config.h"
+#endif
+
+/* In order to avoid warnings on unused arguments */
+#ifndef IDENTIFIER_NOT_USED
+#define IDENTIFIER_NOT_USED(x) (void)(&x)
+#endif
+
+/*
+ * Is NULL defined?
+ */
+#if !defined(NULL)
+#define NULL (void *)0
+#endif
+
+/*************************************************************
+ *
+ * GLOBAL CONSTANTS AND VARIABLES
+ *
+ *************************************************************/
+
+/*
+ * defined in mpa_misc.c
+ */
+extern const mpa_num_base const_largest_deci_base;
+extern const mpa_num_base Const_1_LShift_Base;
+extern const mpa_num_base const_one;
+
+/*************************************************************
+ *
+ * INTERNAL FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * From mpa_mem_static.
+ *
+ */
+
+/*------------------------------------------------------------
+ *
+ * From mpa_addsub.c
+ *
+ */
+void __mpa_full_adder(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *sum, mpa_word_t *carry);
+
+void __mpa_full_sub(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *diff, mpa_word_t *carry);
+
+void __mpa_full_adder_ackum(mpa_word_t *d, mpa_word_t e, mpa_word_t *carry);
+
+void __mpa_abs_add(mpa_word_t *sum,
+ mpa_usize_t *sum_size,
+ const mpa_word_t *op1,
+ mpa_usize_t op1_size,
+ const mpa_word_t *op2, mpa_usize_t op2_size);
+
+void __mpa_abs_add_ackum(mpanum dest, const mpanum src);
+
+void __mpa_abs_sub(mpa_word_t *diff,
+ mpa_usize_t *diff_size,
+ const mpa_word_t *op1,
+ mpa_usize_t op1_size,
+ const mpa_word_t *op2, mpa_usize_t op2_size);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_cmp.c
+ *
+ */
+
+int __mpa_abs_cmp(const mpanum op1, const mpanum op2);
+
+int __mpa_abs_greater_than(const mpanum op1, const mpanum op2);
+
+int __mpa_abs_less_than(const mpanum op1, const mpanum op2);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_mul.c
+ *
+ */
+void __mpa_mul_add_word(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *p, mpa_word_t *carry);
+
+void __mpa_mul_add_word_cum(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *p, mpa_word_t *carry);
+
+void __mpa_abs_mul_word(mpanum dest, const mpanum op1, mpa_word_t op2);
+
+void __mpa_abs_mul(mpanum dest, const mpanum op1, const mpanum op2);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_div.c
+ *
+ */
+
+mpa_word_t __mpa_div_dword(mpa_word_t n0,
+ mpa_word_t n1, mpa_word_t d, mpa_word_t *r);
+
+void __mpa_div_q_r_internal_word(mpanum q,
+ mpanum r,
+ const mpanum op1, const mpa_word_t op2);
+
+void __mpa_div_q_r(mpanum q,
+ mpanum r,
+ const mpanum op1, const mpanum op2, mpa_scratch_mem pool);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_shift.c
+ *
+ */
+
+void __mpa_shift_words_left(mpanum op, mpa_word_t q);
+void __mpa_shift_words_right(mpanum op, mpa_word_t q);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_montgomery.c
+ *
+ */
+
+void __mpa_montgomery_sub_ack(mpanum dest, mpanum src);
+
+void __mpa_montgomery_mul_add(mpanum dest, mpanum src, mpa_word_t w);
+
+void __mpa_montgomery_mul(mpanum dest,
+ mpanum op1, mpanum op2, mpanum n, mpa_word_t n_inv);
+
+/*------------------------------------------------------------
+ *
+ * From mpa_misc.c
+ *
+ */
+void __mpa_set_unused_digits_to_zero(mpanum n);
+
+#endif /* include guard */
diff --git a/lib/libmpa/include/mpalib.h b/lib/libmpa/include/mpalib.h
new file mode 100644
index 0000000..a467e39
--- /dev/null
+++ b/lib/libmpa/include/mpalib.h
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+#ifndef GUARD_MPALIB_H
+#define GUARD_MPALIB_H
+
+/*************************************************************
+ *
+ * How functions are exported.
+ *
+ *************************************************************/
+#define MPALIB_EXPORT
+
+/*************************************************************
+ *
+ * Include common configuration definitions
+ *
+ *************************************************************/
+#include "mpalib_config.h"
+
+/*************************************************************
+ *
+ * TYPE DEFINITIONS
+ *
+ *************************************************************/
+
+#if defined(MPA_SUPPORT_DWORD_T)
+typedef unsigned long long mpa_dword_t;
+#endif
+
+/*! \struct mpa_numbase_struct
+ * The internal representation of a multi precision integer.
+ *
+ * \param alloc The size of the allocated array d in number of mpa_word_t.
+ *
+ * \param size The number of used words in *d to represent the number, or
+ * minus the number if the mpa_numbase is representing a
+ * negative number. The mpa_numbase
+ * is representing zero if and only if size == 0.
+ *
+ * \param d The digits of the integer. The digits are in radix
+ * 2^WORD_SIZE.
+ * The digits are stored in a little endian format, i.e.
+ * the least significant word_t is stored in d[0].
+ *
+ * \internal ** NOTE **
+ * If you change this struct, you must update the const variables
+ * in mpa_misc.c and mpa_primetest.c
+ * And the
+ * MPA_NUMBASE_METADATA_SIZE_IN_U32
+ * below.
+ */
+typedef struct mpa_numbase_struct {
+ mpa_asize_t alloc;
+ mpa_usize_t size;
+ mpa_word_t d[];
+} mpa_num_base;
+
+/*/ mpanum is the type we use as parameters to function calls in this library */
+typedef mpa_num_base *mpanum;
+
+/*!
+ * The Context struct for a Montgomery multiplication
+ *
+ * \internal ** NOTE **
+ * If you change this struct, you must update the
+ * MPA_FMM_CONTEXT_METADATA_SIZE_IN_U32
+ * below.
+ *
+ */
+typedef struct mpa_fmm_context_struct {
+ mpanum r_ptr;
+ mpanum r2_ptr;
+ mpa_word_t n_inv;
+ uint32_t m[];
+} mpa_fmm_context_base;
+
+typedef mpa_fmm_context_base *mpa_fmm_context;
+
+struct mpa_scratch_mem_sync;
+typedef void (mpa_scratch_mem_sync_fn)(struct mpa_scratch_mem_sync *sync);
+
+typedef struct mpa_scratch_mem_struct {
+ uint32_t size; /* size of the memory pool, in bytes */
+ uint32_t bn_bits; /* default size of a temporary variables */
+ uint32_t last_offset; /* offset to the last one */
+ mpa_scratch_mem_sync_fn *get;
+ mpa_scratch_mem_sync_fn *put;
+ struct mpa_scratch_mem_sync *sync;
+ uint32_t m[]; /* mpa_scratch_item are stored there */
+} mpa_scratch_mem_base;
+typedef mpa_scratch_mem_base *mpa_scratch_mem;
+
+struct mpa_scratch_item {
+ uint32_t size; /* total size of this item */
+ /* the offset of the previous and next mpa_scratch_item */
+ uint32_t prev_item_offset;
+ uint32_t next_item_offset;
+ /* followed by a mpa_num_base, being the big number to save */
+};
+
+/*************************************************************
+ *
+ * EXPORTED VARIABLES
+ *
+ *************************************************************/
+
+/*************************************************************
+ *
+ * MACROS
+ *
+ *************************************************************/
+
+#define MPA_STRING_MODE_HEX_UC 16
+#define MPA_STRING_MODE_HEX_LC 17
+
+#define MPA_EVEN_PARITY 0
+#define MPA_ODD_PARITY 1
+
+/*! Returns true if the mpanum 'a' is even (zero included) */
+#define mpa_is_even(a) (mpa_parity((a)) == MPA_EVEN_PARITY)
+/*! Returns true if the mpanum 'a' is odd */
+#define mpa_is_odd(a) (mpa_parity((a)) == MPA_ODD_PARITY)
+/* Short hand for setting the value of 'a' to the value of 'b' */
+#define mpa_set(a, b) mpa_copy((a), (b))
+
+/* */
+/* Define how to convert between sizes given in uint32_t and mpa_word_t */
+/* */
+#define ASIZE_TO_U32(x) (((sizeof(mpa_word_t) * (x)) + 3) / 4)
+#define U32_TO_ASIZE(x) \
+ ((mpa_asize_t)(((4 * (x)) + (sizeof(mpa_word_t) - 1)) / \
+ sizeof(mpa_word_t)))
+
+/*************************************************************
+ *
+ * STATIC MEMORY MODE DEFINES
+ *
+ *************************************************************/
+
+/*
+ * The number of extra uint32_t in the internal representation.
+ * This is used in the static memory mode.
+ * It is chosen to be complient with the requirments of GlobalPlatform.
+ */
+#define MPA_NUMBASE_METADATA_SIZE_IN_U32 2
+
+#define MPA_SCRATCHMEM_METADATA_SIZE_IN_U32 (sizeof(mpa_scratch_mem_base)/ 4)
+
+/*
+ * The size (in uint32_t) of the constituent variables
+ * of mpa_fmm_context apart from m[]
+ */
+
+#define MPA_FMM_CONTEXT_METADATA_SIZE_IN_U32 (sizeof(mpa_fmm_context_base)/4)
+
+/*
+ * This macro returns the size of the complete mpa_num_base struct that
+ * can hold n-bits integers. This is used in the static memory mode.
+ */
+#define mpa_StaticVarSizeInU32(n) \
+ ((((n)+31)/32) + MPA_NUMBASE_METADATA_SIZE_IN_U32)
+
+/*
+ *
+ */
+#define mpa_StaticTempVarSizeInU32(max_bits) \
+ (2 * mpa_StaticVarSizeInU32((max_bits)) - \
+ MPA_NUMBASE_METADATA_SIZE_IN_U32)
+
+/*
+ *
+ */
+#define mpa_scratch_mem_size_in_U32(nr_temp_vars, max_bits) \
+ (((nr_temp_vars) * (mpa_StaticTempVarSizeInU32((max_bits)) + \
+ sizeof(struct mpa_scratch_item))) + \
+ sizeof(struct mpa_scratch_mem_struct))
+
+/*
+ *
+ */
+#define mpa_fmm_context_size_in_U32(n) \
+ (2 * (mpa_StaticVarSizeInU32((n)) + 2) + \
+ MPA_FMM_CONTEXT_METADATA_SIZE_IN_U32)
+
+/*************************************************************
+ *
+ * FUNCTION PROTOTYPES
+ *
+ * All externally available functions from this lib.
+ *
+ *************************************************************/
+
+/*
+ * From mpa_init.c
+ */
+
+/*
+ * mpa_init_scratch_mem
+ * Initiate a chunk of memory to be used as a scratch pool.
+ * The size of the pool (in uint32_t) must corresponde to the
+ * size returned by the macro mpa_ScratchMemSizeInU32
+ * with the same parameters 'nr_vars' and 'max_bits'
+ *
+ * \param pool The pool to initialize
+ * \param size the size, in bytes, of the pool
+ * \prama bn_bits default size, in bits, of a big number
+ * \param get increase reference counter to pool
+ * \param put decrease reference counter to pool
+ * \param sync argument to supply to get() and put()
+ */
+MPALIB_EXPORT void mpa_init_scratch_mem_sync(mpa_scratch_mem pool, size_t size,
+ uint32_t bn_bits, mpa_scratch_mem_sync_fn get,
+ mpa_scratch_mem_sync_fn put,
+ struct mpa_scratch_mem_sync *sync);
+
+MPALIB_EXPORT void mpa_init_scratch_mem(mpa_scratch_mem pool, size_t size,
+ uint32_t bn_bits);
+
+
+/*
+ * mpa_init_static
+ * Initiate a mpanum to hold an integer of a certain size.
+ * The parameter 'len' is the return value of the macro
+ * mpa_StaticVarSizeInU32 called with the max bit size as parameter.
+ *
+ * \param src The mpanum to be initialized
+ * \param len The allocated size in uint32_t of src
+ */
+MPALIB_EXPORT void mpa_init_static(mpanum src, uint32_t len);
+
+MPALIB_EXPORT void mpa_init_static_fmm_context(mpa_fmm_context_base *context,
+ uint32_t len);
+
+/*
+ * From mpa_addsub.c
+ */
+MPALIB_EXPORT void mpa_add(mpanum dest, const mpanum op1, const mpanum op2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_sub(mpanum dest, const mpanum op1, const mpanum op2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_add_word(mpanum dest, const mpanum op1, mpa_word_t op2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_sub_word(mpanum dest, const mpanum op1, mpa_word_t op2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_neg(mpanum dest, const mpanum src);
+
+/*
+ * From mpa_mul.c
+ */
+
+MPALIB_EXPORT void mpa_mul(mpanum dest, const mpanum op1, const mpanum op2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_mul_word(mpanum dest, const mpanum op1, mpa_word_t op2,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_div.c
+ */
+
+MPALIB_EXPORT void mpa_div(mpanum q, mpanum r,
+ const mpanum op1, const mpanum op2,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_modulus.c
+ */
+
+MPALIB_EXPORT void mpa_mod(mpanum dest, const mpanum op, const mpanum n,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_add_mod(mpanum dest, const mpanum op1, const mpanum op2,
+ const mpanum n, mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_sub_mod(mpanum dest, const mpanum op1, const mpanum op2,
+ const mpanum n, mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_mul_mod(mpanum dest, const mpanum op1, const mpanum op2,
+ const mpanum n, mpa_scratch_mem pool);
+
+MPALIB_EXPORT int mpa_inv_mod(mpanum dest, const mpanum op, const mpanum n,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_cmp.c
+ */
+
+MPALIB_EXPORT int32_t mpa_cmp(const mpanum op1, const mpanum op2);
+
+MPALIB_EXPORT int32_t mpa_cmp_short(const mpanum op1, int32_t op2);
+
+/*
+ * From mpa_conv.c
+ */
+
+MPALIB_EXPORT void mpa_set_S32(mpanum dest, int32_t short_val);
+
+MPALIB_EXPORT int32_t mpa_get_S32(int32_t *dest, mpanum src);
+
+MPALIB_EXPORT void mpa_set_word(mpanum dest, mpa_word_t src);
+
+MPALIB_EXPORT mpa_word_t mpa_get_word(mpanum src);
+
+/*
+ * From mpa_shift.c
+ */
+
+MPALIB_EXPORT void mpa_shift_left(mpanum dest, const mpanum src,
+ mpa_word_t steps);
+
+MPALIB_EXPORT void mpa_shift_right(mpanum dest, const mpanum src,
+ mpa_word_t steps);
+
+/*
+ * From mpa_gcd.c
+ */
+MPALIB_EXPORT void mpa_gcd(mpanum dest, const mpanum src1, const mpanum src2,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_extended_gcd(mpanum gcd, mpanum dest1, mpanum dest2,
+ const mpanum src1, const mpanum src2,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_io.c
+ */
+MPALIB_EXPORT int mpa_get_str_size(void);
+
+MPALIB_EXPORT int mpa_set_str(mpanum dest, const char *digitstr);
+
+MPALIB_EXPORT char *mpa_get_str(char *str, int mode, const mpanum n);
+
+MPALIB_EXPORT int mpa_set_oct_str(mpanum dest, const uint8_t *buffer,
+ size_t buffer_len, bool negative);
+
+MPALIB_EXPORT int mpa_get_oct_str(uint8_t *buffer, size_t *buffer_len,
+ const mpanum n);
+
+/*
+ * From mpa_expmod.c
+ */
+MPALIB_EXPORT void mpa_exp_mod(mpanum dest, const mpanum op1, const mpanum op2,
+ const mpanum n, const mpanum r_modn,
+ const mpanum r2_modn, const mpa_word_t n_inv,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_misc.c
+ */
+
+MPALIB_EXPORT void mpa_wipe(mpanum src);
+
+MPALIB_EXPORT void mpa_copy(mpanum dest, const mpanum src);
+
+MPALIB_EXPORT void mpa_abs(mpanum dest, const mpanum src);
+
+MPALIB_EXPORT int mpa_highest_bit_index(const mpanum src);
+
+MPALIB_EXPORT uint32_t mpa_get_bit(const mpanum src, uint32_t idx);
+
+MPALIB_EXPORT int mpa_can_hold(mpanum dest, const mpanum src);
+
+MPALIB_EXPORT int mpa_parity(const mpanum src);
+
+MPALIB_EXPORT mpanum mpa_constant_one(void);
+
+/*
+ * From mpa_Random.c
+ */
+
+typedef uint32_t (*random_generator_cb)(void *buf, size_t blen);
+
+MPALIB_EXPORT void mpa_set_random_generator(random_generator_cb callback);
+
+MPALIB_EXPORT void mpa_get_random(mpanum dest, mpanum limit);
+
+/*
+ * From mpa_montgomery.c
+ */
+MPALIB_EXPORT int mpa_compute_fmm_context(const mpanum modulus, mpanum r_modn,
+ mpanum r2_modn, mpa_word_t *n_inv,
+ mpa_scratch_mem pool);
+
+MPALIB_EXPORT void mpa_montgomery_mul(mpanum dest, mpanum op1, mpanum op2,
+ mpanum n, mpa_word_t n_inv,
+ mpa_scratch_mem pool);
+
+/*
+ * From mpa_mem_static.c
+ */
+MPALIB_EXPORT mpanum mpa_alloc_static_temp_var(mpanum *var,
+ mpa_scratch_mem pool);
+MPALIB_EXPORT mpanum mpa_alloc_static_temp_var_size(int size_bits,
+ mpanum *var,
+ mpa_scratch_mem pool);
+MPALIB_EXPORT void mpa_free_static_temp_var(mpanum *var, mpa_scratch_mem pool);
+
+/*
+ * From mpa_primetest.c
+ */
+MPALIB_EXPORT int mpa_is_prob_prime(mpanum n, int conf_level,
+ mpa_scratch_mem pool);
+
+#endif /* include guard */
diff --git a/lib/libmpa/include/mpalib_config.h b/lib/libmpa/include/mpalib_config.h
new file mode 100644
index 0000000..08ab5e0
--- /dev/null
+++ b/lib/libmpa/include/mpalib_config.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+#ifndef GUARD_MPA_CONFIG_H
+#define GUARD_MPA_CONFIG_H
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/************************************************************************\
+ * Common definitions
+ * You should go through these carefully and adjust to your environment
+ \************************************************************************/
+
+/*
+ * Definitions of different sized integers and unsigned
+ *
+ * mpa_word_t: should be an unsigned int of size equal to the most
+ * efficient add/sub/mul/div word size of the machine.
+ *
+ * mpa_int_t should be a signed int of the same size as the mpa_word_t
+ *
+ * mpa_halfw_t: half size of mpa_word_t
+ *
+ * mpa_asize_t: an unsigned int of suitable size to hold the number of
+ * allocated bytes for the representation. We cannot use size_t
+ * since that is 64 bit long on 64 bit machines, and that is
+ * ridiciously large.
+ *
+ * mpa_usize_t: a signed int suitable to hold the number of used mpa_word_t to
+ * represent the integer.
+ *
+ * mpa_byte_t: the native unsigned byte type.
+ */
+typedef uint32_t mpa_word_t;
+typedef int32_t mpa_int_t;
+typedef uint16_t mpa_halfw_t;
+typedef uint32_t mpa_asize_t;
+typedef int32_t mpa_usize_t;
+typedef uint8_t mpa_byte_t;
+
+/* Number of bits in mpa_word_t */
+#define MPA_WORD_SIZE 32
+
+/* Largest representable number in a mpa_int_t */
+#define MPA_INT_MAX INT32_MAX
+
+/* Smallest representable number in a mpa_int_t */
+#define MPA_INT_MIN INT32_MIN
+
+/* The Log2(MPA_WORD_SIZE) */
+#define MPA_LOG_OF_WORD_SIZE 5
+
+/* The Log2 of number of bytes in a mpa_word_t */
+#define MPA_LOG_OF_BYTES_PER_WORD 2
+
+/* The largest power of 10 representable in a mpa_word_t */
+#define LARGEST_DECIMAL_BASE_IN_WORD 1000000000
+
+/* the number of decimal digits minus 1 in LARGEST_DECIMAL_BASE_IN_WORD */
+#define LARGEST_DECIMAL_BASE_DIGITS 9
+
+/* The largest string size to represent a big number as a string */
+#define MPA_STR_MAX_SIZE (4096 + 2)
+
+/* define MPA_BIG_ENDIAN or MPA_LITTLE_ENDIAN */
+#define MPA_LITTLE_ENDIAN
+/*#define MPA_BIG_ENDIAN */
+
+/*
+ * comment out the line below if your system does not support "unsigned
+ * long long"
+ */
+#define MPA_SUPPORT_DWORD_T
+
+/*
+ * define if you want to use ARM assembler code for certain cruicial
+ * functions
+ */
+/* #define USE_ARM_ASM */
+
+/*
+ * Include functionality for converting to and from strings; mpa_set_string
+ * and mpa_get_string.
+ */
+#define MPA_INCLUDE_STRING_CONVERSION
+
+/*
+ * Quick fix to be able to better define these mem functions later
+ */
+#define MACRO_DEF_MPA_MEMFUNCS
+
+#ifdef MACRO_DEF_MPA_MEMFUNCS
+#include <stdlib.h>
+#include <string.h>
+#define mpa_memset memset
+#define mpa_memcpy memcpy
+#define mpa_memmove memmove
+#endif
+
+#endif /* include guard */
diff --git a/lib/libmpa/mpa_addsub.c b/lib/libmpa/mpa_addsub.c
new file mode 100644
index 0000000..ede3ab7
--- /dev/null
+++ b/lib/libmpa/mpa_addsub.c
@@ -0,0 +1,561 @@
+/*
+ * 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_full_adder
+ *
+ * A word_t sized full adder. Incoming carry is in *carry.
+ * The sum will be put in *sum and the
+ * outgoing carry will be returned in *carry
+ */
+void __mpa_full_adder(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *sum, mpa_word_t *carry)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_dword_t _s;
+ _s = (mpa_dword_t) (a) + (mpa_dword_t) (b) + (mpa_dword_t) (*carry);
+ *sum = (mpa_word_t) (_s);
+ *carry = ((mpa_word_t) (_s >> MPA_WORD_SIZE));
+#else
+ *sum = a + *carry;
+ *carry = (*sum < a);
+ *sum += b;
+ *carry += (*sum < b);
+#endif
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_full_sub
+ *
+ * A word_t sized full subtraction function. Incoming carry is in *carry.
+ * The difference will be put in *diff and the outgoing carry will be returned
+ * in *carry.
+ */
+void __mpa_full_sub(mpa_word_t a,
+ mpa_word_t b, mpa_word_t *diff, mpa_word_t *carry)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_dword_t _d;
+ _d = (mpa_dword_t) (a) - (mpa_dword_t) (b) - (mpa_dword_t) (*carry);
+ *diff = (mpa_word_t) (_d);
+ *carry = 0 - (mpa_word_t) (_d >> WORD_SIZE);
+#else
+ mpa_word_t _d;
+ *diff = a - *carry;
+ *carry = (*diff > a);
+ _d = *diff - b;
+ *carry += (_d > *diff);
+ *diff = _d;
+#endif
+}
+
+/*------------------------------------------------------------
+ *
+ * __mpa_full_adder_ackum
+ *
+ * A word_t sized full adder with ackumulate. *d = *d + e + *carry
+ * Outgoing carry is in *carry
+ */
+void __mpa_full_adder_ackum(mpa_word_t *d, mpa_word_t e, mpa_word_t *carry)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_dword_t _s;
+ _s = (mpa_dword_t) (*d) + (mpa_dword_t) (e) + (mpa_dword_t) (*carry);
+ *d = (mpa_word_t) (_s);
+ *carry = ((mpa_word_t) (_s >> MPA_WORD_SIZE));
+#else
+ mpa_word_t _s;
+ _s = *d + *carry;
+ *carry = (_s < *d);
+ *d = _s + e;
+ *carry += (*d < _s);
+#endif
+}
+
+#endif /* of USR_ARM_ASM */
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_add
+ *
+ * Calculate |op1| + |op2|.
+ * op1 and op2 are pointers to word_t arrays holding the value.
+ * *Sum must be big enough to hold the result.
+ */
+void __mpa_abs_add(mpa_word_t *sum,
+ mpa_usize_t *sum_size,
+ const mpa_word_t *op1,
+ mpa_usize_t op1_size,
+ const mpa_word_t *op2, mpa_usize_t op2_size)
+{
+ const mpa_word_t *smaller;
+ const mpa_word_t *larger;
+ mpa_word_t *sum_begin;
+ mpa_usize_t smaller_wsize; /* size in words of the smallest */
+ mpa_usize_t larger_wsize; /* size in words of the largest */
+ mpa_word_t carry;
+ mpa_usize_t i;
+
+ /* make sure we know which is the larger one */
+ if (op1_size > op2_size) {
+ larger = op1;
+ smaller = op2;
+ larger_wsize = op1_size;
+ smaller_wsize = op2_size;
+ } else { /* op2 is the larger or same size */
+ larger = op2;
+ smaller = op1;
+ larger_wsize = op2_size;
+ smaller_wsize = op1_size;
+ }
+
+ sum_begin = sum;
+ carry = 0;
+ i = 0;
+ while (i < smaller_wsize) {
+ __mpa_full_adder(*(smaller++), *(larger++), sum++, &carry);
+ i++;
+ }
+ while (carry && (i < larger_wsize)) {
+ __mpa_full_adder(0, *(larger++), sum++, &carry);
+ i++;
+ }
+
+ if (i < larger_wsize) {
+ /* carry did not propagate all the way, copy the rest */
+ mpa_memcpy(sum, larger, WORDS_TO_BYTES(larger_wsize - i));
+ sum += larger_wsize - i;
+ }
+
+ if (carry != 0)
+ *(sum++) = carry;
+ *sum_size = (mpa_word_t) (sum - sum_begin);
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_add_ackum
+ *
+ * Calculate dest = dest + src. Both dest and src must be positive
+ * dest must be big enough to hold the result.
+ */
+void __mpa_abs_add_ackum(mpanum dest, const mpanum src)
+{
+ const mpa_word_t *sdig; /* source digits */
+ mpa_word_t *ddig; /* dest digits */
+ mpa_word_t *dest_begin;
+
+ mpa_word_t carry;
+ mpa_usize_t i;
+
+ i = src->size - dest->size;
+ if (i <= 0)
+ i = 0;
+ mpa_memset(dest->d + dest->size, 0, (1 + i) * BYTES_PER_WORD);
+
+ dest_begin = dest->d;
+ sdig = src->d;
+ ddig = dest->d;
+ i = 0;
+ carry = 0;
+ while (i < src->size) {
+ __mpa_full_adder_ackum(ddig++, *(sdig++), &carry);
+ /*
+ * _s = (mpa_dword_t)*(ddig) + (mpa_dword_t)*(sdig++) +
+ * (mpa_dword_t)carry;
+ * *(ddig++) = (mpa_word_t)(_s);
+ * carry = (mpa_word_t)(_s >> WORD_SIZE);
+ */
+ i++;
+ }
+ while (carry) {
+ __mpa_full_adder_ackum(ddig++, 0, &carry);
+ /*
+ * _s = (mpa_dword_t)*(ddig) + (mpa_dword_t)carry;
+ * *(ddig++) = (mpa_word_t)(_s);
+ * carry = (mpa_word_t)(_s >> WORD_SIZE);
+ */
+ }
+ i = (mpa_word_t) (ddig - dest_begin);
+ if (i > dest->size)
+ dest->size = i;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_sub
+ *
+ * Calculate |op1| - |op2|, where |op1| >= |op2| must hold.
+ * op1 and op2 are pointers to word_t arrays holding the value.
+ * *Diff must be big enough to hold the result. diff_size is
+ * updated with the number of significant words in *diff.
+ */
+void __mpa_abs_sub(mpa_word_t *diff,
+ mpa_usize_t *diff_size,
+ const mpa_word_t *op1,
+ mpa_usize_t op1_size,
+ const mpa_word_t *op2, mpa_usize_t op2_size)
+{
+ mpa_word_t carry;
+ mpa_usize_t i;
+
+ carry = 0;
+ i = 0;
+ while (i < op2_size) {
+ __mpa_full_sub(*(op1++), *(op2++), diff++, &carry);
+ i++;
+ }
+ /*
+ * Here we have no more digits in op2, we only need to keep on
+ * subtracting 0 from op1, and deal with carry.
+ */
+ while (carry && (i < op1_size)) {
+ __mpa_full_sub(*(op1++), 0, diff++, &carry);
+ i++;
+ }
+
+ if (i < op1_size) {
+ /*
+ * Carry did not propagate all the way, now we only need to
+ * copy the rest.
+ */
+ mpa_memcpy(diff, op1, WORDS_TO_BYTES(op1_size - i));
+ diff += op1_size - i;
+ }
+ /* check size of diff */
+ i = op1_size;
+ while ((i > 0) && (*(--diff) == 0))
+ i--;
+ *diff_size = i;
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: mpa_add
+ *
+ * Adds op1 and op2 and puts the result in dest. Dest could be one of the
+ * operands.
+ */
+void mpa_add(mpanum dest,
+ const mpanum op1, const mpanum op2, mpa_scratch_mem pool)
+{
+ int sign_1;
+ int sign_2;
+ mpa_word_t size_1;
+ mpa_word_t size_2;
+ mpanum tmp_dest;
+ int mem_marker;
+
+ size_1 = __mpanum_size(op1);
+ size_2 = __mpanum_size(op2);
+
+ sign_1 = __mpanum_sign(op1);
+ sign_2 = __mpanum_sign(op2);
+
+ /* 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;
+
+ /* Check if we must do a subtraction or a addition.
+ * Remember, we're not allowed to modify op1 or op2.
+ */
+
+ if (sign_1 == sign_2) { /* same signs */
+ /* tmp_dest = |op1| + |op2| or tmp_dest = -(|op1| + |op2|) */
+ __mpa_abs_add(tmp_dest->d, &(tmp_dest->size), op1->d, size_1,
+ op2->d, size_2);
+
+ if (sign_1 == MPA_NEG_SIGN)
+ __mpanum_neg(tmp_dest);
+
+ } else { /* different signs */
+ if (sign_1 == MPA_POS_SIGN) { /* op1 positive, op1 + (-op2) */
+ if (__mpa_abs_greater_than(op1, op2)) {
+ /* |op1| > |op2| */
+
+ /* tmp_dest = |op1| - |op2| */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op1->d, size_1, op2->d, size_2);
+
+ } else { /* |op2| >= |op1| */
+ /* tmp_dest = - ( |op2| - |op1|) */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op2->d, size_2, op1->d, size_1);
+ __mpanum_neg(tmp_dest);
+ }
+
+ } else { /* op2 positive, (-op1) + op2 */
+ if (__mpa_abs_greater_than(op1, op2)) {
+ /* |op1| > |op2| */
+
+ /* tmp_dest = - (|op1| - |op2|) */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op1->d, size_1, op2->d, size_2);
+ __mpanum_neg(tmp_dest);
+ } else { /* |op2| >= |op1| */
+ /* tmp_dest = |op2| - |op1| */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op2->d, size_2, op1->d, size_1);
+ }
+ }
+ }
+
+ mpa_copy(dest, tmp_dest);
+ if (mem_marker)
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_sub
+ *
+ * Calculated op1 - op2 and stores the result in dest. Dest could be one of
+ * the operands.
+ */
+void mpa_sub(mpanum dest,
+ const mpanum op1, const mpanum op2, mpa_scratch_mem pool)
+{
+ int sign_1;
+ int sign_2;
+ mpa_word_t size_1;
+ mpa_word_t size_2;
+ mpanum tmp_dest;
+ int mem_marker;
+
+ size_1 = __mpanum_size(op1);
+ size_2 = __mpanum_size(op2);
+
+ sign_1 = __mpanum_sign(op1);
+ sign_2 = __mpanum_sign(op2);
+
+ /* 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;
+
+ /*
+ * Check if we must do a subtraction or a addition. Remember,
+ * we're not allowed to modify op1 or op2.
+ */
+ if (sign_1 == sign_2) { /* same signs */
+ if (sign_1 == MPA_POS_SIGN) { /* both positive, op1 - op2 */
+ if (__mpa_abs_greater_than(op1, op2)) {
+ /* |op1| > |op2| */
+
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op1->d, size_1, op2->d, size_2);
+ } else { /* |op1| <= |op2| */
+ /* tmp_dest = - (|op2| - |op1|) */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op2->d, size_2, op1->d, size_1);
+ __mpanum_neg(tmp_dest);
+ }
+ } else {
+ /* both negative, (-op1) - (-op2) = -(op1 - op2) */
+
+ if (__mpa_abs_greater_than(op1, op2)) {
+ /* |op1| > |op2| */
+
+ /* tmp_dest = -(|op1| - |op2|) */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op1->d, size_1, op2->d, size_2);
+ __mpanum_neg(tmp_dest);
+ } else { /* |op1| <= |op2| */
+ /* tmp_dest = |op2| - |op1| */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size),
+ op2->d, size_2, op1->d, size_1);
+ }
+ }
+ } else { /* different signs */
+ if (sign_1 == MPA_POS_SIGN) { /* op1 positive, op1 - (-op2) */
+ /* tmp_dest = |op1| + |op2| */
+ __mpa_abs_add(tmp_dest->d, &(tmp_dest->size), op1->d,
+ size_1, op2->d, size_2);
+ } else { /* op2 positive, (-op1) - op2 = - (op1 + op2) */
+ /* tmp_dest = -(|op1| + |op2|) */
+ __mpa_abs_add(tmp_dest->d, &(tmp_dest->size), op1->d,
+ size_1, op2->d, size_2);
+ __mpanum_neg(tmp_dest);
+ }
+ }
+
+ mpa_copy(dest, tmp_dest);
+ if (mem_marker)
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_neg
+ *
+ * Assigns dest the value of src, but with a change of sign. Dest and src
+ * could be the same variable.
+ */
+void mpa_neg(mpanum dest, const mpanum src)
+{
+ mpa_copy(dest, src);
+ __mpanum_neg(dest);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_add_word
+ *
+ * Add a word_t (op2) to op1 and put result in dest
+ */
+void mpa_add_word(mpanum dest,
+ const mpanum op1, mpa_word_t op2, mpa_scratch_mem pool)
+{
+ int sign_1;
+ mpanum tmp_dest;
+ mpa_word_t size_1;
+ int mem_marker;
+
+ if (op2 == 0) {
+ mpa_copy(dest, op1);
+ return;
+ }
+
+ if (__mpanum_is_zero(op1)) {
+ dest->size = 1;
+ dest->d[0] = op2;
+ return;
+ }
+
+ sign_1 = __mpanum_sign(op1);
+ size_1 = __mpanum_size(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;
+
+ /* find out if we should do an add or a sub, op2 is always positive */
+ if (sign_1 == MPA_POS_SIGN) { /* add */
+ /* tmp_dest = |op1| + op2 */
+ __mpa_abs_add(tmp_dest->d, &(tmp_dest->size), op1->d, size_1,
+ &op2, 1);
+ } else { /* sub, op1 is negative: (-op1) + op2 */
+ if (__mpanum_size(op1) > 1 || __mpanum_lsw(op1) > op2) {
+ /* |op1| > |op2| */
+
+ /* tmp_dest = - (|op1| - op2) */
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size), op1->d,
+ size_1, &op2, 1);
+ __mpanum_neg(tmp_dest);
+ } else { /* op2 >= |op1| */
+ /* tmp_dest = op2 - |op1| */
+ tmp_dest->d[0] = op2 - op1->d[0];
+ tmp_dest->size = (tmp_dest->d[0] == 0) ? 0 : 1;
+ }
+ }
+
+ mpa_copy(dest, tmp_dest);
+ if (mem_marker)
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_sub_word
+ *
+ * Calculate op1 - op2, op2 is a word_t and always positive.
+ */
+void mpa_sub_word(mpanum dest,
+ const mpanum op1, mpa_word_t op2, mpa_scratch_mem pool)
+{
+ int sign_1;
+ mpanum tmp_dest;
+ mpa_word_t size_1;
+ char mem_marker;
+
+ if (op2 == 0) {
+ mpa_copy(dest, op1);
+ return;
+ }
+
+ if (__mpanum_is_zero(op1)) {
+ dest->size = -1;
+ dest->d[0] = op2;
+ return;
+ }
+
+ sign_1 = __mpanum_sign(op1);
+ size_1 = __mpanum_size(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;
+
+ /*
+ * Find out if we should do an add or a sub, op2 is always positive
+ *
+ * dest = op1 - op2 if op1 > op2 >= 0
+ * dest = -(op2 - op1) if op2 >= op1 >= 0
+ * dest = -(|op1| + op2) if op1 < 0
+ *
+ */
+ if (sign_1 == MPA_POS_SIGN) {
+ if (__mpanum_size(op1) > 1 || __mpanum_lsw(op1) > op2) {
+ __mpa_abs_sub(tmp_dest->d, &(tmp_dest->size), op1->d,
+ size_1, &op2, 1);
+ } else {
+ tmp_dest->d[0] = op2 - op1->d[0];
+ tmp_dest->size = (tmp_dest->d[0] == 0) ? 0 : -1;
+ }
+ } else {
+ __mpa_abs_add(tmp_dest->d, &(tmp_dest->size), op1->d, size_1,
+ &op2, 1);
+ __mpanum_neg(tmp_dest);
+ }
+
+ mpa_copy(dest, tmp_dest);
+ if (mem_marker)
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
diff --git a/lib/libmpa/mpa_cmp.c b/lib/libmpa/mpa_cmp.c
new file mode 100644
index 0000000..5d36bde
--- /dev/null
+++ b/lib/libmpa/mpa_cmp.c
@@ -0,0 +1,171 @@
+/*
+ * 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
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_cmp
+ *
+ * Returns 0 if |op1| == |op2|
+ * >0 if |op1| > |op2|
+ * <0 if |op1| < |op2|
+ */
+int __mpa_abs_cmp(const mpanum op1, const mpanum op2)
+{
+ int wpos;
+ char same;
+
+ /* if they're really the same, return 0 */
+ if (op1 == op2)
+ return 0;
+
+ /* check the sizes */
+ if (__mpanum_size(op1) != __mpanum_size(op2))
+ return __mpanum_size(op1) - __mpanum_size(op2);
+
+ if (__mpanum_is_zero(op1) && __mpanum_is_zero(op2))
+ return 0;
+
+ /* Ok, so we have the same size and they're not zero. Check words */
+ wpos = __mpanum_size(op1) - 1;
+ same = 1;
+ while (same && (wpos >= 0)) {
+ same = (op1->d[wpos] == op2->d[wpos]);
+ wpos--;
+ }
+ if (same)
+ return 0;
+ wpos++;
+ return (op1->d[wpos] > op2->d[wpos] ? 1 : -1);
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_greater_than
+ *
+ * Returns 1 if |op1| > |op2| and otherwise returns 0.
+ */
+int __mpa_abs_greater_than(const mpanum op1, const mpanum op2)
+{
+ return (__mpa_abs_cmp(op1, op2) > 0 ? 1 : 0);
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_abs_less_than
+ *
+ * Returns 1 if |op1| < |op2| and otherwise returns 0.
+ */
+int __mpa_abs_less_than(const mpanum op1, const mpanum op2)
+{
+ return (__mpa_abs_cmp(op1, op2) < 0 ? 1 : 0);
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: mpa_cmp
+ *
+ * Returns 0 if op1 == op2
+ * >0 if op1 > op2
+ * <0 if op1 < op2
+ */
+int32_t mpa_cmp(const mpanum op1, const mpanum op2)
+{
+ int sign_1;
+ int abscmp;
+
+ /* if they have different signs, it's straight forward */
+ sign_1 = __mpanum_sign(op1);
+ if (sign_1 != __mpanum_sign(op2))
+ return sign_1;
+
+ /* handle the special case where op1->size = 0 */
+ if (__mpanum_size(op1) == 0)
+ return __mpanum_size(op2) == 0 ? 0 : -__mpanum_sign(op2);
+
+ /* so they have the same sign. compare the abs values and decide
+ * based on sign_1.
+ */
+
+ abscmp = __mpa_abs_cmp(op1, op2);
+ if (sign_1 != MPA_POS_SIGN)
+ return -abscmp;
+ return abscmp;
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_cmp_short
+ *
+ * Compares op1 to the word_t op2 and returns:
+ * >0 if op1 > op2,
+ * 0 if op1 == op2
+ * <0 if op1 < op2
+ */
+int32_t mpa_cmp_short(const mpanum op1, int32_t op2)
+{
+#if (MPA_WORD_SIZE == 32)
+
+ int sign_1;
+ int sign_2;
+ mpa_word_t op2abs;
+
+ sign_1 = __mpanum_sign(op1);
+ sign_2 = (op2 < 0) ? MPA_NEG_SIGN : MPA_POS_SIGN;
+
+ /* handle the special case where op1->size = 0 */
+ if (op1->size == 0)
+ return op2 == 0 ? 0 : -sign_2;
+
+ /* check if op1 is larger than an int32_t */
+ if (__mpanum_size(op1) > 1)
+ return sign_1;
+
+ /* check if they have different signs */
+ if (sign_1 != sign_2)
+ return sign_1;
+
+ /* here they have the same sign and we can compare absolute values */
+
+ op2abs = ((op2 < 0) ? (mpa_word_t) -op2 : (mpa_word_t) op2);
+
+ if (__mpanum_lsw(op1) == op2abs)
+ return 0;
+
+ return (__mpanum_lsw(op1) > op2abs) ? sign_1 : -sign_1;
+
+#else
+#error "Write code for digit size != 32"
+#endif
+}
diff --git a/lib/libmpa/mpa_conv.c b/lib/libmpa/mpa_conv.c
new file mode 100644
index 0000000..d7de0dd
--- /dev/null
+++ b/lib/libmpa/mpa_conv.c
@@ -0,0 +1,92 @@
+/*
+ * 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"
+
+/*------------------------------------------------------------
+ *
+ * mpa_set_S32
+ *
+ */
+void mpa_set_S32(mpanum dest, int32_t short_val)
+{
+#if (MPA_WORD_SIZE == 32)
+ if (short_val != 0)
+ dest->size = (short_val < 0) ? -1 : 1;
+ else
+ dest->size = 0;
+ dest->d[0] = (short_val < 0) ? -short_val : short_val;
+#else
+#error "Write code for digit size != 32"
+#endif
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_get_S32
+ *
+ * Returns zero if the src fits within an int32_t
+ * otherwise it returns non-zero and the dest value is undefined.
+ */
+int32_t mpa_get_S32(int32_t *dest, mpanum src)
+{
+#if (MPA_WORD_SIZE == 32)
+ if (__mpanum_size(src) > 1)
+ return -1;
+ if (__mpanum_lsw(src) > INT32_MIN && __mpanum_sign(src) == MPA_NEG_SIGN)
+ return -1;
+ if (__mpanum_lsw(src) > INT32_MAX && __mpanum_sign(src) == MPA_POS_SIGN)
+ return -1;
+
+ *dest = __mpanum_get_word(0, src) * __mpanum_sign(src);
+ return 0;
+
+#else
+#error "Write code for digit size != 32"
+#endif
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_set_word
+ *
+ */
+void mpa_set_word(mpanum dest, mpa_word_t src)
+{
+ dest->d[0] = src;
+ dest->size = (src == 0) ? 0 : 1;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_get_word
+ *
+ * Returns the absolute value of the least significant word of src
+ */
+mpa_word_t mpa_get_word(mpanum src)
+{
+ return __mpanum_get_word(0, src);
+}
diff --git a/lib/libmpa/mpa_div.c b/lib/libmpa/mpa_div.c
new file mode 100644
index 0000000..dd764f9
--- /dev/null
+++ b/lib/libmpa/mpa_div.c
@@ -0,0 +1,413 @@
+/*
+ * 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"
+
+/*************************************************************
+ *
+ * HELPER FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * These functions have ARM assembler implementations
+ *
+ */
+#if !defined(USE_ARM_ASM)
+
+static mpa_dword_t __mpa_soft_div(mpa_dword_t num, mpa_word_t den_in,
+ mpa_word_t *rem)
+{
+ mpa_dword_t quot = 0, qbit = 1;
+ mpa_dword_t den = den_in;
+
+ while ((int64_t) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ if (rem)
+ *rem = (mpa_word_t) num;
+
+ return quot;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_div_dword
+ *
+ * Calculates quotient and remainder of (n1*base + n0) / d.
+ * It is assumed that the quotient is small enough to fit a single word.
+ */
+mpa_word_t __mpa_div_dword(mpa_word_t n0,
+ mpa_word_t n1, mpa_word_t d, mpa_word_t *r)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_dword_t n;
+ /* mpa_dword_t tmp_q; */
+
+ n = ((mpa_dword_t) n1 << WORD_SIZE) + n0;
+ return __mpa_soft_div(n, d, r);
+ /* tmp_q = n / d; */
+ /* *r = (mpa_word_t)(n % d); */
+ /* return tmp_q; */
+#else
+#error write non-dword code for __mpa_div_dword
+#endif
+}
+
+#endif /* USE_ARM_ASM */
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_div_q_r_internal
+ *
+ * Finds the quotient and remainder when |op1| is divided by |op2|.
+ * q, r, op1 and op2 must all be distinct and not null.
+ * E.i. we get q and r such that |op1| = q*|op2| + r, 0<= r < |op2|.
+ * Assumptions: |op1| >= |op2| and |op2| >= 2^(WORD_SIZE)
+ *
+ */
+static void __mpa_div_q_r_internal(mpanum q,
+ mpanum r,
+ const mpanum op1,
+ const mpanum op2, mpa_scratch_mem pool)
+{
+ mpa_word_t normshift;
+ int base_diff;
+ int i;
+ int cmp_same;
+ mpa_usize_t n; /* size of op1 */
+ mpa_usize_t t; /* size of op2 */
+ mpa_word_t w1;
+ mpa_word_t w2;
+ mpa_word_t w3;
+ mpa_word_t w4;
+ mpa_word_t w5;
+ mpanum p;
+ mpanum y;
+ mpanum x;
+
+ /*
+ * get temp storage
+ */
+ mpa_alloc_static_temp_var(&p, pool);
+ mpa_alloc_static_temp_var(&y, pool);
+ mpa_copy(y, op2);
+
+ /*
+ * May need a large value for r since op1 may be an "oversized"
+ * value that is reduced. x is used for that internally and it's
+ * initial value is op1.
+ */
+ mpa_alloc_static_temp_var(&x, pool);
+ mpa_copy(x, op1);
+ __mpanum_set_sign(x, MPA_POS_SIGN);
+ __mpanum_set_sign(y, MPA_POS_SIGN);
+
+ /*
+ * Normalization
+ */
+ normshift = 0;
+ w1 = __mpanum_msw(y);
+ while (w1 < ((mpa_word_t)1 << (WORD_SIZE - 1))) {
+ normshift++;
+ w1 <<= 1;
+ }
+ if (normshift) {
+ mpa_shift_left(x, x, normshift);
+ mpa_shift_left(y, y, normshift);
+ }
+
+ n = x->size;
+ t = y->size;
+ base_diff = (int)n - t;
+
+ mpa_wipe(q);
+
+ /*
+ * check if op1 >= op2*base^(base_diff)
+ */
+ /* mpa_shift_left(y, y, base_diff * WORD_SIZE); */
+ __mpa_shift_words_left(y, base_diff);
+
+ i = __mpanum_size(y);
+ cmp_same = 1;
+ while (cmp_same != 0 && i > 0) {
+ i--;
+ cmp_same = (__mpanum_get_word(i, x) == __mpanum_get_word(i, y));
+ }
+ if (!cmp_same && (__mpanum_get_word(i, x) > __mpanum_get_word(i, y))) {
+ q->d[base_diff] = 1;
+ mpa_sub(x, x, y, pool);
+ }
+
+ /* start main division loop */
+ i = x->size - 1;
+ while (i >= (int)t) {
+ if (__mpanum_get_word(i, x) ==
+ __mpanum_get_word(t + base_diff - 1, y)) {
+ q->d[i - t] = WORD_ALL_BITS_ONE;
+ } else {
+ q->d[i - t] =
+ __mpa_div_dword(__mpanum_get_word(i - 1, x),
+ __mpanum_get_word(i, x),
+ __mpanum_get_word(t + base_diff
+ - 1, y),
+ NULL);
+ }
+ while (1) {
+ /* set incoming carry to zero for all three ops */
+ w1 = 0;
+ w3 = 0;
+ w5 = 0;
+ __mpa_mul_add_word(q->d[i - t],
+ __mpanum_get_word(t + base_diff - 1,
+ y), &w2, &w1);
+
+ if (w1 > __mpanum_get_word(i, x))
+ goto loop_dec;
+
+ __mpa_mul_add_word(q->d[i - t],
+ __mpanum_get_word(t + base_diff - 2,
+ y), &w4, &w3);
+
+ __mpa_full_adder(w2, w3, &w3, &w5);
+ w2 = 0; /* used as carry */
+ __mpa_full_adder(w1, w5, &w5, &w2);
+ if (w2 || w5 > __mpanum_get_word(i, x))
+ goto loop_dec;
+ if (w5 < __mpanum_get_word(i, x))
+ break;
+ if (w3 > __mpanum_get_word(i - 1, x))
+ goto loop_dec;
+ if (w3 < __mpanum_get_word(i - 1, x))
+ break;
+ if (w4 > __mpanum_get_word(i - 2, x))
+ goto loop_dec;
+ break;
+loop_dec:
+ q->d[i - t]--;
+ }
+
+ /* mpa_shift_right(y, y, WORD_SIZE); */
+ __mpa_shift_words_right(y, 1);
+ base_diff--;
+ mpa_mul_word(p, y, q->d[i - t], pool);
+ mpa_sub(x, x, p, pool);
+ if (__mpanum_sign(x) == MPA_NEG_SIGN) {
+ mpa_add(x, x, y, pool);
+ q->d[i - t]--;
+ }
+ i--;
+ }
+ /*
+ * Find size of q
+ */
+ i = n - t;
+ while (i >= 0 && q->d[i] == 0)
+ i--;
+ q->size = i + 1;
+ /*
+ * Divide r by the normalization value and copy to output
+ */
+ mpa_shift_right(x, x, normshift);
+ mpa_copy(r, x);
+
+ /*
+ * release p, y, and x
+ */
+ mpa_free_static_temp_var(&p, pool);
+ mpa_free_static_temp_var(&y, pool);
+ mpa_free_static_temp_var(&x, pool);
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_div_q_r_internal_word
+ *
+ * Finds the quotient and remainder when |op1| is divided by |op2|, where
+ * op2 is a word.
+ * q, r and op1 must all be distinct and not null.
+ * E.i. we get q and r such that |op1| = q*|op2| + r, 0<= r < |op2|.
+ * Assumptions: |op1| >= |op2|.
+
+ */
+void __mpa_div_q_r_internal_word(mpanum q,
+ mpanum r,
+ const mpanum op1, const mpa_word_t op2)
+{
+ int pos1;
+ mpa_word_t q_word;
+ mpa_word_t r_word;
+ mpa_word_t n1;
+ mpa_word_t n0;
+ int i;
+
+ if (__mpanum_size(op1) == 1) {
+ mpa_set_word(q, op1->d[0] / op2);
+ mpa_set_word(r, op1->d[0] % op2);
+ return;
+ }
+ mpa_copy(r, op1);
+ mpa_set_word(q, 0);
+
+ pos1 = (int)__mpanum_size(r) - 1;
+ n1 = 0;
+ n0 = r->d[pos1];
+ while (pos1 >= 0) {
+ q_word = __mpa_div_dword(n0, n1, op2, &r_word);
+ q->d[pos1] = q_word;
+ r->d[pos1] = r_word;
+ n1 = r->d[pos1];
+ n0 = r->d[--pos1];
+ }
+ /* set sizes of r and q */
+ r->size = (r->d[0] == 0 ? 0 : 1);
+ i = __mpanum_size(op1) - 1;
+ while (i >= 0 && q->d[i] == 0)
+ i--;
+ q->size = i + 1;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_div_q_r
+ *
+ * Calculates the quotient and remainder when op1 is divided by op2.
+ * q, r, op1 and op2 must all be distinct and not null, except that op1
+ * may be equal to op2.
+ * There must be enough space allocated in q and r to handle the results.
+ * If op2 is zero a division with zero will be executed and the above layers
+ * can handle that as it pleases.
+ * The sign of q and r are shown in the table:
+ * __________________________________
+ * | Sign(q/r) | op1 >= 0 | op1 < 0 |
+ * |--------------------------------|
+ * | op2 > 0 | +/+ | -/- |
+ * |--------------------------------|
+ * | op2 < 0 | -/+ | +/- |
+ * |________________________________|
+ */
+void __mpa_div_q_r(mpanum q,
+ mpanum r,
+ const mpanum op1, const mpanum op2, mpa_scratch_mem pool)
+{
+ int q_sign;
+ int cmp;
+
+ if (__mpanum_is_zero(op1)) {
+ mpa_set_word(q, 0);
+ mpa_set_word(r, 0);
+ return;
+ }
+ if (__mpanum_is_zero(op2)) {
+ /* generate a divide by zero error */
+ q_sign = 42 / op2->size;
+ return;
+ }
+
+ q_sign =
+ (__mpanum_sign(op1) !=
+ __mpanum_sign(op2)) ? MPA_NEG_SIGN : MPA_POS_SIGN;
+ cmp = __mpa_abs_cmp(op1, op2);
+ if (cmp == 0) {
+ mpa_set_word(q, 1);
+ mpa_set_word(r, 0);
+ return;
+ }
+ if (cmp > 0) { /* |op1| > |op2| */
+ if (__mpanum_size(op2) > 1)
+ __mpa_div_q_r_internal(q, r, op1, op2, pool);
+ else
+ __mpa_div_q_r_internal_word(q, r, op1, op2->d[0]);
+ } else { /* |op1| < |op2| */
+ mpa_set_word(q, 0);
+ mpa_copy(r, op1);
+ return;
+ }
+ __mpanum_set_sign(q, q_sign);
+ __mpanum_set_sign(r, __mpanum_sign(op1));
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: mpa_div
+ *
+ * Returns the quotient and the remainder of op1 divided by op2.
+ * q and r must be distinct variables.
+ * This function returns q and r such that
+ * op1 = q*op2 + r
+ * where 0 <= r < |op2|
+ */
+void mpa_div(mpanum q,
+ mpanum r, const mpanum op1, const mpanum op2, mpa_scratch_mem pool)
+{
+ mpanum tmp_q;
+ mpanum tmp_r;
+ char mem_marker_q;
+ char mem_marker_r;
+
+ /* handle the case when q is one of the operands or zero */
+ if (q == op1 || q == op2 || q == 0) {
+ mpa_alloc_static_temp_var(&tmp_q, pool);
+ mem_marker_q = 1;
+ } else {
+ tmp_q = q;
+ mem_marker_q = 0;
+ }
+
+ /* handle the case when r is one of the operands or zero */
+ if (r == op1 || r == op2 || r == 0) {
+ mpa_alloc_static_temp_var(&tmp_r, pool);
+ mem_marker_r = 1;
+ } else {
+ tmp_r = r;
+ mem_marker_r = 0;
+ }
+
+ __mpa_div_q_r(tmp_q, tmp_r, op1, op2, pool);
+
+ if (q != 0)
+ mpa_copy(q, tmp_q);
+ if (mem_marker_q)
+ mpa_free_static_temp_var(&tmp_q, pool);
+ if (r != 0)
+ mpa_copy(r, tmp_r);
+ if (mem_marker_r)
+ mpa_free_static_temp_var(&tmp_r, pool);
+}
diff --git a/lib/libmpa/mpa_expmod.c b/lib/libmpa/mpa_expmod.c
new file mode 100644
index 0000000..d02c784
--- /dev/null
+++ b/lib/libmpa/mpa_expmod.c
@@ -0,0 +1,85 @@
+/*
+ * 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"
+
+/*------------------------------------------------------------
+ *
+ * mpa_exp_mod
+ *
+ * Calculates dest = op1 ^ op2 mod n
+ *
+ */
+void mpa_exp_mod(mpanum dest,
+ const mpanum op1,
+ const mpanum op2,
+ const mpanum n,
+ const mpanum r_modn,
+ const mpanum r2_modn,
+ const mpa_word_t n_inv, mpa_scratch_mem pool)
+{
+ mpanum A;
+ mpanum B;
+ mpanum xtilde;
+ mpanum *ptr_a;
+ mpanum *ptr_b;
+ mpanum *swapper;
+ int idx;
+
+ mpa_alloc_static_temp_var(&A, pool);
+ mpa_alloc_static_temp_var(&B, pool);
+ mpa_alloc_static_temp_var(&xtilde, pool);
+
+ /* transform to Montgomery space */
+ /* use internal version since xtidle is big enough */
+ __mpa_montgomery_mul(xtilde, op1, r2_modn, n, n_inv);
+
+ mpa_copy(A, r_modn);
+ ptr_a = &A;
+ ptr_b = &B;
+ __mpa_set_unused_digits_to_zero(A);
+ __mpa_set_unused_digits_to_zero(B);
+ for (idx = mpa_highest_bit_index(op2); idx >= 0; idx--) {
+ __mpa_montgomery_mul(*ptr_b, *ptr_a, *ptr_a, n, n_inv);
+ if (mpa_get_bit(op2, idx) == 1) {
+ __mpa_montgomery_mul(*ptr_a, *ptr_b, xtilde, n, n_inv);
+ } else {
+ swapper = ptr_a;
+ ptr_a = ptr_b;
+ ptr_b = swapper;
+ }
+ }
+
+ /* transform back form Montgomery space */
+ __mpa_montgomery_mul(*ptr_b, (const mpanum)&const_one, *ptr_a,
+ n, n_inv);
+
+ mpa_copy(dest, *ptr_b);
+
+ mpa_free_static_temp_var(&A, pool);
+ mpa_free_static_temp_var(&B, pool);
+ mpa_free_static_temp_var(&xtilde, pool);
+}
diff --git a/lib/libmpa/mpa_gcd.c b/lib/libmpa/mpa_gcd.c
new file mode 100644
index 0000000..79b82c5
--- /dev/null
+++ b/lib/libmpa/mpa_gcd.c
@@ -0,0 +1,372 @@
+/*
+ * 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"
+
+/*************************************************************
+ *
+ * HELPER FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * __mpa_divby2
+ *
+ */
+static void __mpa_divby2(mpanum op)
+{
+ mpa_word_t i;
+ /* The bit of the word which will be shifted into another word. */
+ mpa_word_t rbit;
+ int msw_became_zero;
+
+ if (__mpanum_is_zero(op))
+ return;
+
+ msw_became_zero = ((__mpanum_msw(op) >> 1) == 0) ? 1 : 0;
+
+ op->d[0] = op->d[0] >> 1;
+ for (i = 1; i < __mpanum_size(op); i++) {
+ rbit = op->d[i] & 0x01;
+ op->d[i] = op->d[i] >> 1;
+ op->d[i - 1] ^= (rbit << (WORD_SIZE - 1));
+ }
+ /* update the size of dest */
+ if (__mpanum_sign(op) == MPA_NEG_SIGN)
+ op->size += msw_became_zero;
+ else
+ op->size -= msw_became_zero;
+}
+
+/*------------------------------------------------------------
+ *
+ * __mpa_mulby2
+ *
+ */
+/*
+static void __mpa_mulby2(mpanum op)
+{
+ mpa_word_t i;
+ mpa_word_t rbit;
+ mpa_word_t need_extra_word;
+
+ if (__mpanum_is_zero(op))
+ return;
+
+ need_extra_word = (__mpanum_msw(op) & (1 << (WORD_SIZE - 1)))?1:0;
+
+ if (need_extra_word)
+ i = __mpanum_size(op);
+ else
+ i = __mpanum_size(op) - 1;
+ while (i > 0) {
+ rbit = op->d[i-1] >> (WORD_SIZE - 1);
+ op->d[i] = op->d[i] << 1;
+ op->d[i] ^= rbit;
+ i--;
+ }
+ rbit = op->d[0] >> (WORD_SIZE - 1);
+
+ if (__mpanum_sign(op) == MPA_POS_SIGN)
+ op->size += need_extra_word;
+ else
+ op->size -= need_extra_word;
+}
+*/
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_egcd
+ *
+ * Given non-negative integers x and y where y < x, we compute
+ * gcd, a and b such that
+ * a*x + b*y = gcd
+ *
+ * gcd must be distrinct and non-zero, that is,
+ * it cannot point to the same mpanum as x_in or y_in or be a null pointer.
+ */
+static void __mpa_egcd(mpanum gcd,
+ mpanum a,
+ mpanum b,
+ const mpanum x_in,
+ const mpanum y_in, mpa_scratch_mem pool)
+{
+ mpanum A;
+ mpanum B;
+ mpanum C;
+ mpanum D;
+ mpanum x;
+ mpanum y;
+ mpanum u;
+ mpa_word_t k;
+
+ /* have y < x from assumption */
+ if (__mpanum_is_zero(y_in)) {
+ if (a != 0)
+ mpa_set_word(a, 1);
+ if (b != 0)
+ mpa_set_word(b, 0);
+ mpa_copy(gcd, x_in);
+ return;
+ }
+ mpa_alloc_static_temp_var(&x, pool);
+ mpa_copy(x, x_in);
+ mpa_alloc_static_temp_var(&y, pool);
+ mpa_copy(y, y_in);
+
+ k = 0;
+ while (mpa_is_even(x) && mpa_is_even(y)) {
+ k++;
+ __mpa_divby2(x);
+ __mpa_divby2(y);
+ }
+
+ mpa_alloc_static_temp_var(&u, pool);
+ mpa_copy(u, x);
+ mpa_copy(gcd, y);
+ mpa_alloc_static_temp_var(&A, pool);
+ mpa_set_word(A, 1);
+ mpa_alloc_static_temp_var(&B, pool);
+ mpa_set_word(B, 0);
+ mpa_alloc_static_temp_var(&C, pool);
+ mpa_set_word(C, 0);
+ mpa_alloc_static_temp_var(&D, pool);
+ mpa_set_word(D, 1);
+
+ while (!__mpanum_is_zero(u)) {
+ while (mpa_is_even(u)) {
+ __mpa_divby2(u);
+ if (mpa_is_odd(A) || mpa_is_odd(B)) {
+ mpa_add(A, A, y, pool);
+ mpa_sub(B, B, x, pool);
+ }
+ __mpa_divby2(A);
+ __mpa_divby2(B);
+ }
+
+ while (mpa_is_even(gcd)) {
+ __mpa_divby2(gcd);
+ if (mpa_is_odd(C) || mpa_is_odd(D)) {
+ mpa_add(C, C, y, pool);
+ mpa_sub(D, D, x, pool);
+ }
+ __mpa_divby2(C);
+ __mpa_divby2(D);
+ }
+
+ if (mpa_cmp(u, gcd) >= 0) {
+ mpa_sub(u, u, gcd, pool);
+ mpa_sub(A, A, C, pool);
+ mpa_sub(B, B, D, pool);
+ } else {
+ mpa_sub(gcd, gcd, u, pool);
+ mpa_sub(C, C, A, pool);
+ mpa_sub(D, D, B, pool);
+ }
+ }
+
+ /* copy results */
+ if (a != 0)
+ mpa_copy(a, C);
+ if (b != 0)
+ mpa_copy(b, D);
+ mpa_shift_left(gcd, gcd, k);
+
+ mpa_free_static_temp_var(&A, pool);
+ mpa_free_static_temp_var(&B, pool);
+ mpa_free_static_temp_var(&C, pool);
+ mpa_free_static_temp_var(&D, pool);
+ mpa_free_static_temp_var(&x, pool);
+ mpa_free_static_temp_var(&y, pool);
+ mpa_free_static_temp_var(&u, pool);
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_gcd
+ * Computes the gcd of x and y where y <= x.
+ * Destination variable gcd must be allocated.
+ */
+static void __mpa_gcd(mpanum gcd,
+ const mpanum x_in,
+ const mpanum y_in, mpa_scratch_mem pool)
+{
+ mpanum x;
+ mpanum y;
+ mpanum t;
+ mpa_word_t k;
+
+ /* have y < x from assumption */
+ if (__mpanum_is_zero(y_in)) {
+ mpa_copy(gcd, x_in);
+ return;
+ }
+ mpa_alloc_static_temp_var(&x, pool);
+ mpa_copy(x, x_in);
+ mpa_alloc_static_temp_var(&y, pool);
+ mpa_copy(y, y_in);
+
+ k = 0;
+ while (mpa_is_even(x) && mpa_is_even(y)) {
+ k++;
+ __mpa_divby2(x);
+ __mpa_divby2(y);
+ }
+
+ mpa_alloc_static_temp_var(&t, pool);
+ while (!__mpanum_is_zero(x)) {
+ while (mpa_is_even(x))
+ __mpa_divby2(x);
+
+ while (mpa_is_even(y))
+ __mpa_divby2(y);
+
+ mpa_sub(t, x, y, pool);
+ /* abs val of t */
+ __mpanum_set_sign(t, MPA_POS_SIGN);
+ __mpa_divby2(t);
+ if (mpa_cmp(x, y) >= 0)
+ mpa_copy(x, t);
+ else
+ mpa_copy(y, t);
+ }
+
+ mpa_shift_left(gcd, y, k);
+ mpa_free_static_temp_var(&t, pool);
+ mpa_free_static_temp_var(&x, pool);
+ mpa_free_static_temp_var(&y, pool);
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: mpa_gcd
+ *
+ * Computes the GCD of src1 and src2
+ */
+void mpa_gcd(mpanum dest,
+ const mpanum src1, const mpanum src2, mpa_scratch_mem pool)
+{
+ int cmp;
+ int sign1;
+ int sign2;
+
+ /* remember sign and take abs value */
+ sign1 = __mpanum_sign(src1);
+ sign2 = __mpanum_sign(src2);
+ __mpanum_set_sign(src1, MPA_POS_SIGN);
+ __mpanum_set_sign(src2, MPA_POS_SIGN);
+
+ cmp = mpa_cmp(src1, src2);
+ if (cmp == 0) {
+ mpa_copy(dest, src1);
+ goto cleanup;
+ }
+ if (cmp < 0) { /* src1 < src2, swap data */
+ __mpa_gcd(dest, src2, src1, pool);
+ } else {
+ __mpa_gcd(dest, src1, src2, pool);
+ }
+
+cleanup:
+ /* restore sign */
+ __mpanum_set_sign(src1, sign1);
+ __mpanum_set_sign(src2, sign2);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_extended_gcd
+ *
+ * Computes gcd, dest1 and dest2 such that
+ * dest1*src1 + dest2*src2 = gcd
+ *
+ * May be called with gcd, dest1 and/or dest2 == 0.
+ *
+ */
+void mpa_extended_gcd(mpanum gcd,
+ mpanum dest1,
+ mpanum dest2,
+ const mpanum src1,
+ const mpanum src2, mpa_scratch_mem pool)
+{
+ int cmp;
+ int sign1;
+ int sign2;
+ int mem_marker;
+ mpanum tmp_gcd;
+
+ if (dest1 == 0 && dest2 == 0) {
+ if (gcd != 0)
+ mpa_gcd(gcd, src1, src2, pool);
+ return;
+ }
+
+ /* remember sign and take abs value */
+ sign1 = __mpanum_sign(src1);
+ sign2 = __mpanum_sign(src2);
+ __mpanum_set_sign(src1, MPA_POS_SIGN);
+ __mpanum_set_sign(src2, MPA_POS_SIGN);
+
+ cmp = mpa_cmp(src1, src2);
+ if (cmp == 0) {
+ if (gcd != 0)
+ mpa_copy(gcd, src1);
+ if (dest1 != 0)
+ mpa_set_word(dest1, 1);
+ if (dest2 != 0)
+ mpa_set_word(dest2, 0);
+ goto cleanup;
+ }
+
+ mem_marker = (gcd == 0 || gcd == src1 || gcd == src2);
+ if (mem_marker)
+ mpa_alloc_static_temp_var(&tmp_gcd, pool);
+ else
+ tmp_gcd = gcd;
+
+ if (cmp < 0) /* src1 < src2, swap data */
+ __mpa_egcd(tmp_gcd, dest2, dest1, src2, src1, pool);
+ else
+ __mpa_egcd(tmp_gcd, dest1, dest2, src1, src2, pool);
+
+ if (gcd != 0)
+ mpa_copy(gcd, tmp_gcd);
+ if (mem_marker)
+ mpa_free_static_temp_var(&tmp_gcd, pool);
+
+cleanup:
+ /* restore sign */
+ __mpanum_set_sign(src1, sign1);
+ __mpanum_set_sign(src2, sign2);
+ /* change resulting signs if needed */
+ if (sign1 == MPA_NEG_SIGN && dest1 != 0)
+ __mpanum_neg(dest1);
+ if (sign2 == MPA_NEG_SIGN && dest2 != 0)
+ __mpanum_neg(dest2);
+}
diff --git a/lib/libmpa/mpa_init.c b/lib/libmpa/mpa_init.c
new file mode 100644
index 0000000..35a6356
--- /dev/null
+++ b/lib/libmpa/mpa_init.c
@@ -0,0 +1,69 @@
+/*
+ * 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"
+
+/*
+ * mpa_init_static
+ */
+void mpa_init_static(mpanum src, uint32_t len)
+{
+ src->alloc = U32_TO_ASIZE(len - MPA_NUMBASE_METADATA_SIZE_IN_U32);
+ src->size = 0;
+ if (src->alloc > 0)
+ src->d[0] = 0;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_InitStaticFMMContext
+ *
+ */
+void mpa_init_static_fmm_context(mpa_fmm_context_base *context, uint32_t len)
+{
+ mpa_asize_t m_alloc;
+
+ m_alloc =
+ U32_TO_ASIZE((mpa_asize_t) len -
+ (mpa_asize_t) MPA_FMM_CONTEXT_METADATA_SIZE_IN_U32);
+ /* clear the array before halfing into r and r2 */
+ mpa_memset(context->m, 0, m_alloc * BYTES_PER_WORD);
+ m_alloc /= 2;
+
+ /* setup context content */
+ context->n_inv = 0;
+
+ context->r_ptr = (void *)context->m;
+ context->r_ptr->alloc =
+ m_alloc - U32_TO_ASIZE(MPA_NUMBASE_METADATA_SIZE_IN_U32);
+ context->r_ptr->size = 0;
+
+ context->r2_ptr = (void *)(context->m + m_alloc);
+ context->r2_ptr->alloc =
+ m_alloc - U32_TO_ASIZE(MPA_NUMBASE_METADATA_SIZE_IN_U32);
+ context->r2_ptr->size = 0;
+}
diff --git a/lib/libmpa/mpa_io.c b/lib/libmpa/mpa_io.c
new file mode 100644
index 0000000..3290ac3
--- /dev/null
+++ b/lib/libmpa/mpa_io.c
@@ -0,0 +1,538 @@
+/*
+ * 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 <assert.h>
+#include <mpa.h>
+#include <trace.h>
+
+/*
+ * Big #ifdef to get rid of string conversion routines
+ */
+#if defined(MPA_INCLUDE_STRING_CONVERSION)
+
+/*************************************************************
+ *
+ * HELPERS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_isspace
+ *
+ * Returns 1 if c is a while space character
+ */
+static int __mpa_isspace(char c)
+{
+ return c == '_' || /* allow underscore which makes long hex */
+ /* numbers easier to read */
+ c == ' ' || /* space */
+ c == '\n' || /* new line */
+ c == '\r' || /* carriage return */
+ c == '\t'; /* tab */
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_is_char_in_base
+ *
+ * Returns 1 if c is either a white space char or a char in the current base,
+ * and 0 otherwise.
+ */
+static int __mpa_is_char_in_base(int base, int c)
+{
+ if (__mpa_isspace(c))
+ return 1;
+
+ switch (base) {
+ case 10:
+ return (c >= '0') && (c <= '9');
+ case 16:
+ return ((c >= '0') && (c <= '9')) ||
+ ((c >= 'A') && (c <= 'F')) ||
+ ((c >= 'a') && (c <= 'f'));
+ default:
+ return 0;
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_digit_value
+ *
+ * Returns the integer value of the hexadecimal character c.
+ */
+static int __mpa_digit_value(int c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+
+ /* defensive */
+ return 0;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_digitstr_to_binary_wsize
+ *
+ * Returns the maximum number of words needed to binary represent a number
+ * consisting of "digits" digits and each digits is in base "base".
+ */
+static mpa_word_t __mpa_digitstr_to_binary_wsize_base_16(int digits)
+{
+ return (digits + 7) >> 3;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_nibble_to_char
+ *
+ * caseing = 1 is lower case, 0 is uppercase
+ */
+static char __mpa_nibble_to_char(mpa_word_t c, int caseing)
+{
+ c &= 0xf;
+ if (c < 0xa)
+ return '0' + (char)c;
+ return caseing == 0 ? 'A' - 0xA + (char)c: 'a' - 0xa + (char)c;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_word_to_hexstr
+ *
+ * caseing 8= 1 is lower case, 0 is uppercase
+ */
+static void __mpa_word_to_hexstr(char *str, mpa_word_t w, int caseing)
+{
+ int i;
+ for (i = NIBBLES_PER_WORD; i > 0; i--) {
+ str[i - 1] =
+ __mpa_nibble_to_char(NIBBLE_OF_WORD(i - 1, w), caseing);
+ }
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_mpanum_to_hexstr
+ *
+ * caseing = 1 is lower case, 0 is uppercase
+ */
+static int __mpa_mpanum_to_hexstr(char *str, int caseing, const mpanum n)
+{
+ int d_idx;
+ char digits[NIBBLES_PER_WORD];
+ int i;
+ char *cptr;
+ int hex_digits;
+
+ /* get high word with data in, watch out for zero case */
+ d_idx = __mpanum_size(n);
+ if (d_idx == 0) {
+ *str++ = '0';
+ *str = '\0';
+ return 1;
+ }
+ d_idx--;
+
+ cptr = str;
+
+ /* the msw is special, since if we should not print leading zeros.
+ */
+ __mpa_word_to_hexstr(digits, n->d[d_idx], caseing);
+
+ /* find the left-most non-zero digit */
+ i = NIBBLES_PER_WORD;
+ while (i-- > 0)
+ if (digits[i] != '0')
+ break;
+ while (i >= 0)
+ *str++ = digits[i--];
+
+ /* convert each word to a hex string */
+ d_idx--;
+ while (d_idx >= 0) {
+ __mpa_word_to_hexstr(digits, n->d[d_idx], caseing);
+ i = NIBBLES_PER_WORD - 1;
+ while (i >= 0)
+ *str++ = digits[i--];
+ d_idx--;
+ }
+ hex_digits = (int)(str - cptr);
+ *str++ = '\0';
+ return hex_digits;
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_count_leading_zero_bits
+ *
+ *
+ */
+static mpa_word_t __mpa_count_leading_zero_bits(mpa_word_t w)
+{
+ mpa_word_t mask;
+ mpa_word_t zeros;
+
+ if (w == 0)
+ return MPA_WORD_SIZE;
+ mask = ((mpa_word_t)1 << (MPA_WORD_SIZE - 1));
+ zeros = 0;
+ while (!(w & mask)) {
+ zeros++;
+ mask >>= 1;
+ }
+ return zeros;
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_SizeInBase
+ *
+ * Returns the number of characters needed to print |n| in base 255.
+ */
+static mpa_word_t __mpa_size_in_base_255(const mpanum n)
+{
+ mpa_word_t totalbits;
+ /* number of leading zero bits in the msw of n */
+ mpa_word_t zerobits_msw;
+
+ if (__mpanum_is_zero(n))
+ return 1;
+
+ zerobits_msw = __mpa_count_leading_zero_bits(
+ n->d[__mpanum_size(n) - 1]);
+ totalbits = WORD_SIZE * __mpanum_size(n) - zerobits_msw;
+
+ return (totalbits + 7) / 8;
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_get_str_size
+ *
+ * Return the max size of the string representing a Big Number
+ */
+int mpa_get_str_size(void)
+{
+ return MPA_STR_MAX_SIZE;
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: mpa_set_str
+ *
+ * Assigns dest the value of the digitstr, where digitstr is a character
+ * string.
+ * If the digitstr starts with a valid number, the valid part will be
+ * converted and the rest of the digitstr will not be parsed further.
+ * digitstr is assumed to be in base 16.
+ * Returns -1 if the digitstr was malformed, and the number of base digits
+ * converted (not including leading zeros) if the conversion was OK.
+ * If the digitstr is a null-ptr we return -1.
+ * If the digitstr is empty, we don't touch dest and just returns 0.
+ * If the digitstr only consists of white spaces, we set dest to zero
+ * returns 0.
+ */
+int mpa_set_str(mpanum dest, const char *digitstr)
+{
+ /* length of digitstr after removal of base indicator and spaces */
+ int dlen;
+ int negative; /* ==1 if number is negative, 0 otherwise */
+ int c; /* value of characters in digitstr */
+ /* a buffer holding the integer values of the digits */
+ static unsigned char buf[MPA_STR_MAX_SIZE];
+ /* number of digits in digitstr which has been place in buf */
+ int bufidx;
+ const char *endp; /* points to the end of digitstr */
+ int retval;
+ /*
+ * Pointer intto dest->d where we should put the next word during
+ * conversion.
+ */
+ mpa_word_t *w;
+ int i; /* loop variable */
+
+ /* some basic sanity checks first */
+ if (*digitstr == 0)
+ return 0;
+
+ /* remove leading spaces */
+ do {
+ c = (unsigned char)*digitstr++;
+ } while (__mpa_isspace(c));
+
+ /* check negative sign */
+ negative = 0;
+ if (c == '-') {
+ negative = 1;
+ c = (unsigned char)*digitstr++;
+ }
+ if (c == '\0') {
+ mpa_set_word(dest, 0);
+ return 0;
+ }
+
+ /* see if we have a '0x' prefix */
+ if (c == '0') {
+ c = (unsigned char)*digitstr++;
+ if (c == 'x' || c == 'X')
+ c = (unsigned char)*digitstr++;
+ }
+
+ /* skip leading zeros and spaces */
+ while (c == '0' || __mpa_isspace(c))
+ c = (unsigned char)*digitstr++;
+
+ /* check if we had a simple "0" string */
+ if (c == '\0') {
+ mpa_set_word(dest, 0);
+ return 0;
+ }
+
+ /* find the end of digitstr */
+ endp = digitstr;
+ while (*endp != 0)
+ endp++;
+
+ /* + 1 since we have one character in 'c' */
+ dlen = (int)(endp - digitstr) + 1;
+ if (dlen > MPA_STR_MAX_SIZE) {
+ EMSG("data len (%d) > max size (%d)", dlen, MPA_STR_MAX_SIZE);
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* convert to a buffer of bytes */
+ bufidx = 0;
+ while (__mpa_is_char_in_base(16, c)) {
+ if (!__mpa_isspace(c))
+ buf[bufidx++] = __mpa_digit_value(c);
+ c = (unsigned char)*digitstr++;
+ }
+
+ if (bufidx == 0) {
+ retval = -1;
+ goto cleanup;
+ }
+ if (__mpa_digitstr_to_binary_wsize_base_16(bufidx) >
+ __mpanum_alloced(dest)) {
+ EMSG("binary buffer (%d) > alloced buffer (%d)",
+ __mpa_digitstr_to_binary_wsize_base_16(bufidx),
+ __mpanum_alloced(dest));
+ retval = -1;
+ goto cleanup;
+ }
+
+ retval = bufidx;
+ w = dest->d;
+ mpa_set_word(dest, 0);
+ /* start converting */
+ *w = 0;
+ i = BYTES_PER_WORD;
+ dest->size = 1;
+ bufidx--; /* dec to get inside buf range */
+ while (bufidx > 1) {
+ *w ^= ((((mpa_word_t)buf[bufidx - 1] << 4) ^ (buf[bufidx])) <<
+ ((mpa_word_t)(BYTES_PER_WORD - i) << 3));
+ i--;
+ bufidx -= 2;
+ if (i == 0) {
+ w++;
+ *w = 0;
+ i = BYTES_PER_WORD;
+ dest->size++;
+ }
+ }
+ if (bufidx == 1)
+ *w ^= ((((mpa_word_t)buf[bufidx - 1] << 4) ^ (buf[bufidx])) <<
+ ((mpa_word_t)(BYTES_PER_WORD - i) << 3));
+ if (bufidx == 0)
+ *w ^= ((mpa_word_t)buf[bufidx] <<
+ ((mpa_word_t)(BYTES_PER_WORD - i) << 3));
+
+ if (negative)
+ __mpanum_neg(dest);
+
+cleanup:
+ return retval;
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_get_str
+ *
+ * Prints a representation of n into str.
+ * The length allocated is the space needed to print n plus additional
+ * chars for the minus sign and the terminating '\0' char.
+ * A pointer to str is returned. If something went wrong, we return 0.
+ *
+ * mode is one of the following:
+ * MPA_STRING_MODE_HEX_UC hex notation using upper case
+ * MPA_STRING_MODE_HEX_LC hex notation using lower case
+ *
+ */
+char *mpa_get_str(char *str, int mode, const mpanum n)
+{
+ char *s = str;
+
+ assert(str);
+
+ /* insert a minus sign */
+ if (__mpanum_sign(n) == MPA_NEG_SIGN) {
+ *s = '-';
+ s++;
+ }
+ switch (mode) {
+ case MPA_STRING_MODE_HEX_UC:
+ __mpa_mpanum_to_hexstr(s, 0, n);
+ break;
+ case MPA_STRING_MODE_HEX_LC:
+ __mpa_mpanum_to_hexstr(s, 1, n);
+ break;
+ default:
+ return 0;
+ }
+
+ return str;
+}
+
+#endif /* #if defined (MPA_INCLUDE_STRING_CONVERSION) */
+
+static mpa_word_t set_word(const uint8_t *in, size_t in_len)
+{
+ int i;
+ mpa_word_t out;
+
+ out = 0;
+ for (i = in_len - 1; i >= 0; i--)
+ out |= (mpa_word_t)in[i] << ((in_len - i - 1) * 8);
+ return out;
+}
+
+int mpa_set_oct_str(mpanum dest, const uint8_t *buffer, size_t buffer_len,
+ bool negative)
+{
+ const uint8_t *buf = buffer;
+ int bufidx = buffer_len;
+ mpa_word_t *w;
+
+ /* Strip of leading zero octets */
+ while (bufidx > 0) {
+ if (*buf != 0)
+ break;
+ bufidx--;
+ buf++;
+ }
+
+ if (bufidx == 0) {
+ mpa_set_word(dest, 0);
+ return 0;
+ }
+
+ /*
+ * bufidx is now indexing one byte past past the last byte in the octet
+ * string relative to buf.
+ */
+
+ if ((size_t) (bufidx - 1) > (BYTES_PER_WORD * __mpanum_alloced(dest)))
+ return -1; /* No space */
+
+ w = dest->d;
+ mpa_set_word(dest, 0);
+ /* start converting */
+ dest->size = 0;
+ while (bufidx > 0) {
+ int l = __MIN(BYTES_PER_WORD, bufidx);
+
+ bufidx -= l;
+ *w = set_word(buf + bufidx, l);
+ w++;
+ dest->size++;
+ }
+
+ if (negative)
+ __mpanum_neg(dest);
+
+ return 0;
+}
+
+static void get_word(mpa_word_t in, uint8_t out[BYTES_PER_WORD])
+{
+ int i;
+
+ for (i = BYTES_PER_WORD - 1; i >= 0; i--) {
+ out[i] = in & UINT8_MAX;
+ in >>= 8;
+ }
+}
+
+int mpa_get_oct_str(uint8_t *buffer, size_t *buffer_len, const mpanum n)
+{
+ size_t req_blen = __mpa_size_in_base_255(n);
+ uint8_t first_word[BYTES_PER_WORD];
+ size_t bufidx = 0;
+ int d_idx;
+ int i;
+
+ if (*buffer_len < req_blen) {
+ *buffer_len = req_blen;
+ return -1;
+ }
+ /* get high word with data in, watch out for zero case */
+ d_idx = __mpanum_size(n);
+ if (d_idx == 0) {
+ memset(buffer, 0, *buffer_len);
+ goto out;
+ }
+ d_idx--;
+
+ /* Strip of leading zero octets */
+ get_word(n->d[d_idx], first_word);
+
+ for (i = 0; i < BYTES_PER_WORD; i++) {
+ if (first_word[i] != 0) {
+ memcpy(buffer, first_word + i, BYTES_PER_WORD - i);
+ bufidx = BYTES_PER_WORD - i;
+ break;
+ }
+ }
+ d_idx--;
+
+ while (d_idx >= 0) {
+ if (bufidx > req_blen)
+ return -1;
+ get_word(n->d[d_idx], buffer + bufidx);
+
+ bufidx += BYTES_PER_WORD;
+ d_idx--;
+ }
+
+out:
+ *buffer_len = req_blen;
+ return 0;
+}
+
+/* end of file mpa_io.c */
diff --git a/lib/libmpa/mpa_mem_static.c b/lib/libmpa/mpa_mem_static.c
new file mode 100644
index 0000000..1debbb4
--- /dev/null
+++ b/lib/libmpa/mpa_mem_static.c
@@ -0,0 +1,177 @@
+/*
+ * 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"
+#include <util.h>
+#include <trace.h>
+
+/*
+ * mpa_init_scratch_mem_sync
+ */
+void mpa_init_scratch_mem_sync(mpa_scratch_mem pool, size_t size,
+ uint32_t bn_bits, mpa_scratch_mem_sync_fn get,
+ mpa_scratch_mem_sync_fn put,
+ struct mpa_scratch_mem_sync *sync)
+{
+ pool->size = size;
+ pool->last_offset = 0; /* nothing is allocated yet in the pool */
+ pool->bn_bits = bn_bits * 2;
+ pool->get = get;
+ pool->put = put;
+ pool->sync = sync;
+}
+
+void mpa_init_scratch_mem(mpa_scratch_mem pool, size_t size, uint32_t bn_bits)
+{
+ mpa_init_scratch_mem_sync(pool, size, bn_bits, NULL, NULL, NULL);
+}
+
+/*
+ * The allocation of the temporary Big Number is called when a temporary
+ * variable is used in Big Number computation: Big Number operations (add,...),
+ * crypto algorithms (rsa, ecc,,...)
+ * The allocation algorithm takes Big Numbers from a pool, characterized by
+ * (cf. struct mpa_scratch_mem_struct):
+ * - the total size (in bytes) of the pool
+ * - the default size (bits) of a big number that will be required
+ * it equals the max size of the computation (for example 4096 bits),
+ * multiplied by 2 to allow overflow in computation
+ * - the offset of the last Big Number item allocated in the pool
+ * (struct mpa_scratch_item). This offset is 0 is nothing is allocated yet.
+ *
+ * Each item consists of (struct mpa_scratch_item)
+ * - the size of the item
+ * - the offsets, in the pool, of the previous and next items
+ *
+ * The allocation allocates an item for a given size of Big Number.
+ * The allocation is performed in the pool after the last
+ * allocated items. This means:
+ * - the heap is never used.
+ * - there is no assumption on the size of the allocated Big Number. Only
+ * the size of the pool will limit the allocation. This allow to
+ * allocate "small" Big Numbers, such in ECC where we know they are
+ * less than 521 bits.
+ * - a constant time allocation and free as there is no list scan
+ * - but a potentially fragmented memory as the allocation does not take into
+ * account "holes" in the pool (allocation is performed after the last
+ * allocated variable). Indeed, this it does not happen to be an issue
+ * as the variables are used as temporary variables, that is
+ * - have a short life cycle
+ * - if a variable A is allocated before a variable B, then A should be
+ * released after B.
+ * So the potential fragmentation is mitigated.
+ */
+mpanum mpa_alloc_static_temp_var_size(int size_bits, mpanum *var,
+ mpa_scratch_mem pool)
+{
+ uint32_t offset;
+ size_t size;
+ struct mpa_scratch_item *new_item;
+ struct mpa_scratch_item *last_item = NULL;
+
+ if (pool->get)
+ pool->get(pool->sync);
+
+ if (!pool->last_offset)
+ offset = sizeof(struct mpa_scratch_mem_struct);
+ else {
+ offset = pool->last_offset;
+ last_item = (struct mpa_scratch_item *)
+ ((vaddr_t)pool + offset);
+ offset += last_item->size;
+ }
+
+ offset = ROUNDUP(offset, sizeof(uint32_t));
+ if (offset > pool->size)
+ goto error;
+
+ size = sizeof(struct mpa_scratch_item) +
+ mpa_StaticVarSizeInU32(size_bits) * sizeof(uint32_t);
+ size = ROUNDUP(size, sizeof(uint32_t));
+ if (offset + size > pool->size)
+ goto error;
+
+ new_item = (struct mpa_scratch_item *)((vaddr_t)pool + offset);
+ new_item->size = size;
+ new_item->prev_item_offset = pool->last_offset;
+ if (last_item)
+ last_item->next_item_offset = offset;
+ new_item->next_item_offset = 0;
+ pool->last_offset = offset;
+
+ *var = (mpanum)(new_item + 1);
+ mpa_init_static(*var, mpa_StaticVarSizeInU32(size_bits));
+ return *var;
+
+error:
+ *var = 0;
+ if (pool->put)
+ pool->put(pool->sync);
+ return 0;
+}
+
+
+mpanum mpa_alloc_static_temp_var(mpanum *var, mpa_scratch_mem pool)
+{
+ return mpa_alloc_static_temp_var_size(pool->bn_bits, var, pool);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_free_static_temp_var
+ *
+ */
+void mpa_free_static_temp_var(mpanum *var, mpa_scratch_mem pool)
+{
+ struct mpa_scratch_item *item;
+ struct mpa_scratch_item *prev_item;
+ struct mpa_scratch_item *next_item;
+ uint32_t last_offset = 0;
+
+ if (!var || !(*var))
+ return;
+
+ item = (struct mpa_scratch_item *)((vaddr_t)(*var) -
+ sizeof(struct mpa_scratch_item));
+ if (item->prev_item_offset) {
+ prev_item = (struct mpa_scratch_item *)((vaddr_t)pool +
+ item->prev_item_offset);
+ prev_item->next_item_offset = item->next_item_offset;
+ last_offset = item->prev_item_offset;
+ }
+
+ if (item->next_item_offset) {
+ next_item = (struct mpa_scratch_item *)((vaddr_t)pool +
+ item->next_item_offset);
+ next_item->prev_item_offset = item->prev_item_offset;
+ last_offset = pool->last_offset;
+ }
+
+ pool->last_offset = last_offset;
+ if (pool->put)
+ pool->put(pool->sync);
+}
+
diff --git a/lib/libmpa/mpa_misc.c b/lib/libmpa/mpa_misc.c
new file mode 100644
index 0000000..a7a996d
--- /dev/null
+++ b/lib/libmpa/mpa_misc.c
@@ -0,0 +1,189 @@
+/*
+ * 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"
+
+/*************************************************************
+ *
+ * GLOBAL CONSTANTS
+ *
+ *************************************************************/
+
+const mpa_num_base const_largest_deci_base = {
+ 1, 1, {LARGEST_DECIMAL_BASE_IN_WORD} };
+const mpa_num_base Const_1_LShift_Base = { 2, 2, {0, 1} };
+const mpa_num_base const_one = { 1, 1, {1} };
+
+/*************************************************************
+ *
+ * HELPERS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_set_unused_digits_to_zero
+ *
+ *
+ */
+void __mpa_set_unused_digits_to_zero(mpanum n)
+{
+ int i;
+
+ /*
+ * Pointer arithmetics on *mpa_word_t will put the
+ * pointer at the right place.
+ */
+ i = __mpanum_size(n);
+ mpa_memset((n->d) + i, 0, (n->alloc - i) * BYTES_PER_WORD);
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * mpa_wipe
+ *
+ * fills the digits with zero and set size = 0;
+ *
+ */
+void mpa_wipe(mpanum var)
+{
+ mpa_memset(var->d, 0, var->alloc * BYTES_PER_WORD);
+ var->size = 0;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_copy
+ *
+ * Copies src to dest.
+ *
+ * Doesn't check if src fits into dest
+ *
+ */
+void mpa_copy(mpanum dest, const mpanum src)
+{
+ if (dest == src)
+ return;
+
+ mpa_memcpy(dest->d, src->d, __mpanum_size(src) * BYTES_PER_WORD);
+ dest->size = src->size;
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_abs
+ * Computes the absolut value of src and puts it in dest
+ * dest and src can be the same mpanum
+ */
+void mpa_abs(mpanum dest, const mpanum src)
+{
+ mpa_copy(dest, src);
+ __mpanum_set_sign(dest, MPA_POS_SIGN);
+}
+
+/* --------------------------------------------------------------------
+ * Function: mpa_highest_bit_index
+ * Returns the index of the highest 1 in |src|.
+ * The index starts at 0 for the least significant bit.
+ * If src == zero, it will return -1
+ *
+ */
+int mpa_highest_bit_index(const mpanum src)
+{
+ mpa_word_t w;
+ mpa_word_t b;
+
+ if (__mpanum_is_zero(src))
+ return -1;
+
+ w = __mpanum_msw(src);
+
+ for (b = 0; b < WORD_SIZE; b++) {
+ w >>= 1;
+ if (w == 0)
+ break;
+ }
+ return (int)(__mpanum_size(src) - 1) * WORD_SIZE + b;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_get_bit
+ *
+ * Returns the value of the idx:th bit in src.
+ * if idx is larger than the number of bits in src,
+ * it returns zero.
+ *
+ */
+uint32_t mpa_get_bit(const mpanum src, uint32_t idx)
+{
+ mpa_word_t w; /* word of bitIndex */
+ unsigned long b; /* bit number in that word */
+
+ w = idx >> LOG_OF_WORD_SIZE;
+ b = idx & (WORD_SIZE - 1);
+
+ if (w > __mpanum_size(src))
+ return 0;
+ b = (1ul << b);
+ return ((src->d[w] & b) != 0);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_CanHold
+ *
+ * returns 1 if dest can hold src without overflowing, 0 otherwise
+ */
+int mpa_can_hold(mpanum dest, const mpanum src)
+{
+ return (__mpanum_alloced(dest) >= __mpanum_size(src) ? 1 : 0);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_parity
+ *
+ */
+int mpa_parity(const mpanum src)
+{
+ return (((__mpanum_lsw(src) & 0x01) ==
+ 0) ? MPA_EVEN_PARITY : MPA_ODD_PARITY);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_constant_one
+ *
+ */
+mpanum mpa_constant_one(void)
+{
+ return (mpanum)&const_one;
+}
diff --git a/lib/libmpa/mpa_modulus.c b/lib/libmpa/mpa_modulus.c
new file mode 100644
index 0000000..5942942
--- /dev/null
+++ b/lib/libmpa/mpa_modulus.c
@@ -0,0 +1,144 @@
+/*
+ * 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"
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * mpa_mod
+ *
+ */
+void mpa_mod(mpanum dest, const mpanum op, const mpanum n, mpa_scratch_mem pool)
+{
+ mpa_div(NULL, dest, op, n, pool);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_add_mod
+ *
+ */
+void mpa_add_mod(mpanum dest,
+ const mpanum op1,
+ const mpanum op2, const mpanum n, mpa_scratch_mem pool)
+{
+ mpanum tmp_dest;
+
+ mpa_alloc_static_temp_var(&tmp_dest, pool);
+
+ mpa_add(tmp_dest, op1, op2, pool);
+ mpa_div(NULL, dest, tmp_dest, n, pool);
+
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_sub_mod
+ *
+ */
+void mpa_sub_mod(mpanum dest,
+ const mpanum op1,
+ const mpanum op2, const mpanum n, mpa_scratch_mem pool)
+{
+ mpanum tmp_dest;
+
+ mpa_alloc_static_temp_var(&tmp_dest, pool);
+
+ mpa_sub(tmp_dest, op1, op2, pool);
+ mpa_div(NULL, dest, tmp_dest, n, pool);
+
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_mul_mod
+ *
+ */
+void mpa_mul_mod(mpanum dest,
+ const mpanum op1,
+ const mpanum op2, const mpanum n, mpa_scratch_mem pool)
+{
+ mpanum tmp_dest;
+
+ mpa_alloc_static_temp_var(&tmp_dest, pool);
+
+ mpa_mul(tmp_dest, op1, op2, pool);
+ mpa_div(NULL, dest, tmp_dest, n, pool);
+
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_inv_mod
+ *
+ */
+int mpa_inv_mod(mpanum dest,
+ const mpanum op, const mpanum n, mpa_scratch_mem pool)
+{
+ mpanum gcd;
+ mpanum tmp_dest;
+ int mem_marker;
+ int res;
+
+ if (mpa_cmp_short(op, 1) == 0) {
+ mpa_set_S32(dest, 1);
+ return 0;
+ }
+
+ mem_marker = (dest == op);
+ if (mem_marker)
+ mpa_alloc_static_temp_var(&tmp_dest, pool);
+ else
+ tmp_dest = dest;
+
+ mpa_alloc_static_temp_var(&gcd, pool);
+ /* The function mpa_extended_gcd behaves badly if tmp_dest = op */
+ mpa_extended_gcd(gcd, tmp_dest, NULL, op, n, pool);
+ res = mpa_cmp_short(gcd, 1);
+
+ if (mem_marker) {
+ mpa_copy(dest, tmp_dest);
+ mpa_free_static_temp_var(&tmp_dest, pool);
+ }
+
+ mpa_free_static_temp_var(&gcd, pool);
+ if (res == 0) {
+ while (mpa_cmp_short(dest, 0) < 0)
+ mpa_add(dest, dest, n, pool);
+ return 0;
+ } else {
+ return -1;
+ }
+}
diff --git a/lib/libmpa/mpa_montgomery.c b/lib/libmpa/mpa_montgomery.c
new file mode 100644
index 0000000..ecea0fb
--- /dev/null
+++ b/lib/libmpa/mpa_montgomery.c
@@ -0,0 +1,266 @@
+/*
+ * 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_montgomery_mul_add
+ * Calculates dest = dest + src*w
+ * Dest must be big enough to hold the result
+ */
+void __mpa_montgomery_mul_add(mpanum dest, mpanum src, mpa_word_t w)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_dword_t a;
+ mpa_word_t *ddig;
+ int32_t idx;
+ mpa_word_t carry;
+ mpa_word_t *dest_begin;
+
+ if (w == 0)
+ return;
+ dest_begin = dest->d;
+ ddig = dest->d;
+ carry = 0;
+ for (idx = 0; idx < src->size; idx++) {
+ a = (mpa_dword_t) *ddig +
+ (mpa_dword_t) src->d[idx] * (mpa_dword_t) w +
+ (mpa_dword_t) (carry);
+ *(ddig++) = (mpa_word_t) (a);
+ carry = (mpa_word_t) (a >> WORD_SIZE);
+ }
+ while (carry) {
+ a = (mpa_dword_t) (*ddig) + (mpa_dword_t) (carry);
+ *(ddig++) = (mpa_word_t) (a);
+ carry = (mpa_word_t) (a >> WORD_SIZE);
+ }
+ idx = (mpa_word_t) (ddig - dest_begin);
+ if (idx > dest->size)
+ dest->size = idx;
+
+#else
+#error write non-dword code for __mpa_montgomery_mul_add
+#endif
+}
+
+/* --------------------------------------------------------------------
+ * Function: __mpa_montgomery_sub_ack
+ * Calculates dest = dest - src
+ * Assumption: dest >= src and both non-negative
+ * and dest > src.
+ *
+ */
+void __mpa_montgomery_sub_ack(mpanum dest, mpanum src)
+{
+#if defined(MPA_SUPPORT_DWORD_T)
+ mpa_word_t *ddig;
+ mpa_word_t carry;
+ int32_t idx;
+ mpa_dword_t a;
+
+ ddig = dest->d;
+ carry = 0;
+ idx = 0;
+ while (idx < src->size) {
+ a = (mpa_dword_t) (*ddig) - (mpa_dword_t) src->d[idx] -
+ (mpa_dword_t) carry;
+ *(ddig++) = (mpa_word_t) (a);
+ carry = 0 - (mpa_word_t) (a >> WORD_SIZE);
+ idx++;
+ }
+ /* Here we have no more digits in op2, we only need to keep on
+ * subtracting 0 from op1, and deal with carry */
+ while (carry) {
+ a = (mpa_dword_t) (*ddig) - (mpa_dword_t) carry;
+ *(ddig++) = (mpa_word_t) (a);
+ carry = 0 - (mpa_word_t) (a >> WORD_SIZE);
+ idx++;
+ }
+ if (idx >= dest->size) {
+ /* carry did propagate all the way, fix size */
+ while (dest->size > 0 && *(--ddig) == 0)
+ dest->size--;
+ }
+#else
+#error write non-dword code for __mpa_montgomery_sub_ack
+#endif
+}
+
+#endif /* USE_ARM_ASM */
+
+/*------------------------------------------------------------
+ *
+ * __mpa_montgomery_mul
+ *
+ * NOTE:
+ * Dest need to be able to hold one more word than the size of n
+ *
+ */
+void __mpa_montgomery_mul(mpanum dest, mpanum op1, mpanum op2, mpanum n,
+ mpa_word_t n_inv)
+{
+ mpa_word_t u;
+ mpa_usize_t idx;
+
+ /* set dest to zero (with all unused digits to zero as well) */
+ mpa_wipe(dest);
+
+ for (idx = 0; idx < n->size; idx++) {
+ u = (dest->d[0] +
+ __mpanum_get_word(idx, op1) *
+ __mpanum_get_word(0, op2)) * n_inv;
+
+ __mpa_montgomery_mul_add(dest, op2,
+ __mpanum_get_word(idx, op1));
+ __mpa_montgomery_mul_add(dest, n, u);
+
+ /* Shift right one mpa_word */
+ dest->size--;
+ for (mpa_usize_t i = 0; i < dest->size; i++)
+ dest->d[i] = dest->d[i + 1];
+ *(dest->d + dest->size) = 0; /* set unused digit to zero. */
+ }
+
+ /* check if dest > n, if so set dest = dest - n */
+ if (__mpa_abs_cmp(dest, n) >= 0)
+ __mpa_montgomery_sub_ack(dest, n);
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/*
+ * mpa_compute_fmm_context
+ */
+int mpa_compute_fmm_context(const mpanum modulus,
+ mpanum r_modn,
+ mpanum r2_modn,
+ mpa_word_t *n_inv,
+ mpa_scratch_mem pool)
+{
+ mpa_usize_t s;
+ int cmpresult;
+ mpanum tmp_n_inv;
+ mpanum gcd;
+
+ /* create a small mpanum on the stack */
+ uint32_t n_lsw_u32[MPA_NUMBASE_METADATA_SIZE_IN_U32 + ASIZE_TO_U32(1)];
+ mpanum n_lsw = (void *)n_lsw_u32;
+
+ /*
+ * compute r to be
+ * 1 << (__mpanum_size(Modulus) * WORD_SIZE) mod modulus
+ */
+ s = __mpanum_size(modulus);
+ mpa_set_word(r_modn, 1);
+ mpa_shift_left(r_modn, r_modn, s * WORD_SIZE);
+ mpa_mod(r_modn, r_modn, modulus, pool);
+
+ /* compute r^2 mod modulus */
+ mpa_mul_mod(r2_modn, r_modn, r_modn, modulus, pool);
+
+ /* Compute the inverse of modulus mod 1 << WORD_SIZE */
+ n_lsw->alloc = 1;
+ n_lsw->size = 1;
+ n_lsw->d[0] = __mpanum_lsw(modulus);
+
+ mpa_alloc_static_temp_var(&tmp_n_inv, pool);
+ mpa_alloc_static_temp_var(&gcd, pool);
+
+ mpa_extended_gcd(gcd, tmp_n_inv, NULL, n_lsw,
+ (const mpanum)&Const_1_LShift_Base, pool);
+ cmpresult = mpa_cmp_short(gcd, 1);
+
+ if (cmpresult != 0)
+ goto cleanup;
+
+ /*
+ * We need the number n' (n_inv) such that
+ *
+ * R*r' - N*n' == 1
+ *
+ * and Extended_GCD gives us the solution to
+ *
+ * R*r' + N*n' == 1
+ *
+ * So if n' is negative, we just forget about the sign.
+ * If n' is positive, we need to subtract R to get
+ * the right residue class.
+ */
+ if (__mpanum_sign(tmp_n_inv) == MPA_POS_SIGN) {
+ mpa_sub(tmp_n_inv, tmp_n_inv,
+ (const mpanum)&Const_1_LShift_Base, pool);
+ }
+ /* then take the absolute value */
+ *n_inv = __mpanum_lsw(tmp_n_inv);
+
+cleanup:
+
+ mpa_free_static_temp_var(&gcd, pool);
+ mpa_free_static_temp_var(&tmp_n_inv, pool);
+
+ if (cmpresult != 0)
+ return -1;
+ return 0;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_montgomery_mul
+ *
+ * wrapper that uses a temp variables for dest, since
+ * that need to be one word larger that n.
+ */
+void mpa_montgomery_mul(mpanum dest,
+ mpanum op1,
+ mpanum op2,
+ mpanum n, mpa_word_t n_inv, mpa_scratch_mem pool)
+{
+ mpanum tmp_dest;
+
+ mpa_alloc_static_temp_var(&tmp_dest, pool);
+
+ __mpa_montgomery_mul(tmp_dest, op1, op2, n, n_inv);
+
+ mpa_copy(dest, tmp_dest);
+ mpa_free_static_temp_var(&tmp_dest, pool);
+}
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);
+}
diff --git a/lib/libmpa/mpa_primetable.h b/lib/libmpa/mpa_primetable.h
new file mode 100644
index 0000000..38c0616
--- /dev/null
+++ b/lib/libmpa/mpa_primetable.h
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+#ifndef GUARD_PRIMETABLE_H
+#define GUARD_PRIMETABLE_H
+
+#include <stdint.h>
+
+/* Primes Number Table
+ * All numbers up to 49999 are represented
+ * by a bit in the following array.
+ * A 0 means composite and a 1 mean a prime.
+ * For an odd number 3<= n <= 49999 we can find out
+ * if n is a prime by doing:
+ * n = (n-3)>>1;
+ * IsPrime = (PRIME_TABLE[n>>5] >> (n & 0x1f)) & 0x1) == 1;
+ * E.i., the primality of each odd number is stored as a bit.
+ */
+const uint32_t MAX_TABULATED_PRIME = 49999;
+const uint32_t NR_STORED_PRIMES = 5133;
+const uint32_t PRIME_TABLE[782] = {
+ 0x325a65b7, 0x40b6894d, 0xc3252619, 0x90cb4106, 0x2d021a64, 0x5244b090,
+ 0x94c308a2, 0x25144168,
+ 0x99212018, 0x841a4c90, 0x21128325, 0x8a452442, 0x36182102, 0x05a05a04,
+ 0x09288450, 0x32824494,
+ 0x4026184c, 0xc009224b, 0xa0892110, 0x60108264, 0x004c1699, 0x84022480,
+ 0x41344b40, 0x110412d8,
+ 0xa05144a4, 0x4802132c, 0x1821a003, 0x34804922, 0x04044108, 0x092086d2,
+ 0x12006030, 0x04309169,
+ 0xc10d8242, 0x00886980, 0x60225001, 0x0a48b011, 0x02532006, 0x04904a69,
+ 0x0029104a, 0x26510804,
+ 0x2880c100, 0xd2458408, 0xa2184d12, 0x01a60840, 0x40291281, 0x10422484,
+ 0x0c001928, 0x1208a051,
+ 0x80c20094, 0x0520d000, 0x1b002289, 0x94930004, 0x6030c141, 0x88080240,
+ 0x24110036, 0x6106132c,
+ 0x1244a408, 0x22902c10, 0x0c801244, 0x08601281, 0x008a0434, 0x40141965,
+ 0x13258200, 0x30480980,
+ 0x6812c041, 0x19080080, 0x90c32186, 0x21840008, 0x08240212, 0x80494806,
+ 0x00169021, 0x12440483,
+ 0x84996020, 0x29804104, 0xcb400440, 0x200040a0, 0x04240824, 0x902c244b,
+ 0x10406194, 0x49304a01,
+ 0x11409000, 0x02d00822, 0x2480c820, 0x00050210, 0xa41a4492, 0x60164009,
+ 0x920014c1, 0x04000422,
+ 0x29021b4c, 0x02680242, 0x22484500, 0x0c329941, 0x81050048, 0x14012000,
+ 0x49025220, 0x43088218,
+ 0x16002104, 0x64840229, 0x89243042, 0x22124c84, 0x01801200, 0x8800108a,
+ 0x02990d00, 0x20201044,
+ 0x42618483, 0x301800a0, 0x08b4010c, 0x51010648, 0x94c30002, 0x41120a44,
+ 0x40042081, 0x04400c82,
+ 0x21340908, 0x81000252, 0x06030830, 0x09008008, 0xca019008, 0x32892110,
+ 0x05064a0c, 0x8a009402,
+ 0x20520514, 0x00a00068, 0x90208248, 0xa4412016, 0x08001060, 0x12040098,
+ 0x12422c82, 0x41148100,
+ 0x012c3080, 0x240b40a4, 0x08908008, 0x50650003, 0x82000120, 0x21005848,
+ 0x83408602, 0x128a2404,
+ 0x08929049, 0x43050050, 0x24016086, 0x04229000, 0x034c0019, 0x00110982,
+ 0x40a40241, 0x0941220a,
+ 0xa0080c12, 0x68144021, 0x12409002, 0x96006c32, 0x20840904, 0x81000051,
+ 0x20906520, 0x0c008860,
+ 0x520c0252, 0x904a0910, 0x01205041, 0x02402219, 0x06000c00, 0x45304320,
+ 0x89443200, 0x00410082,
+ 0x6080d125, 0x8204b088, 0xb0004400, 0x04205a00, 0x40018083, 0x024a2004,
+ 0x40149045, 0x81290601,
+ 0x00422100, 0x01324240, 0x18002419, 0x10912022, 0x61840100, 0x10680250,
+ 0x200b0c20, 0x29140020,
+ 0x8a410448, 0x84080c00, 0x05204104, 0x40499050, 0x10006004, 0x00828029,
+ 0x0308a008, 0x80004106,
+ 0x4d224825, 0x48401400, 0x84832502, 0x00140121, 0x800c009a, 0xa24004b2,
+ 0x01120001, 0x8a2430c1,
+ 0x14090020, 0x28841a00, 0x48090282, 0x30424494, 0x08248809, 0x4124a013,
+ 0x00884880, 0x44201205,
+ 0x02082608, 0x16512800, 0x05244820, 0x092800d8, 0x82520004, 0x49145004,
+ 0x88218001, 0xa0900110,
+ 0x04001940, 0x80290602, 0x10422490, 0x40808108, 0x91202408, 0xb4c20080,
+ 0x64009860, 0x00442201,
+ 0x16810086, 0x00308960, 0x18600050, 0x840900a0, 0x40001005, 0x4200a04a,
+ 0x00190020, 0x05804208,
+ 0x83008012, 0x20c24514, 0x04040840, 0xc001a64a, 0xa04b2000, 0x28101020,
+ 0x51449291, 0x10522020,
+ 0x00944301, 0x08251090, 0x040a0004, 0x21128220, 0x08219081, 0x90804902,
+ 0x0c265008, 0xc2018491,
+ 0x020844a0, 0x00921141, 0x4204040a, 0x04806084, 0x4520d821, 0x1b400001,
+ 0x92502482, 0x01000048,
+ 0x814920ca, 0x84030400, 0x68008004, 0x4044940b, 0xb4000030, 0x28064800,
+ 0x40200090, 0x20982120,
+ 0x40929000, 0x0024a003, 0x24890084, 0x0c105000, 0x53008298, 0x14120800,
+ 0x64100100, 0x09440010,
+ 0x00494806, 0x21009301, 0x0200248b, 0x00812112, 0x0d064044, 0x00080440,
+ 0x224a0130, 0x08b48044,
+ 0x50090418, 0x00420992, 0x60328041, 0x18001408, 0x80900182, 0x64008308,
+ 0x10610040, 0x86410804,
+ 0x29060109, 0xd8002003, 0x00882030, 0x0802434c, 0x0a490442, 0x20c020b0,
+ 0x4082080d, 0x9020a011,
+ 0x20802914, 0x08301a04, 0x08009400, 0x04420020, 0x24104821, 0x01290202,
+ 0x02100400, 0x0006c100,
+ 0x88012041, 0xa0102402, 0x0080004c, 0x00601203, 0x10824134, 0x04220809,
+ 0x53200002, 0x848b6810,
+ 0x01209264, 0x49048610, 0x00000920, 0x21848020, 0x814c1042, 0x80120880,
+ 0x01801221, 0x18208448,
+ 0x26102c12, 0x08044140, 0x83409292, 0x100804a0, 0x4022080c, 0x92250008,
+ 0x144a0086, 0x60001840,
+ 0x42083001, 0x04800106, 0x0400c101, 0x10610208, 0x020304b4, 0x0880000c,
+ 0x88058448, 0x06014110,
+ 0x00045b08, 0x81208013, 0x10922500, 0x4012100d, 0x80012200, 0x80012016,
+ 0x08104a45, 0x53481000,
+ 0x960009a0, 0x00b0c308, 0x010820c0, 0x24184082, 0x28141024, 0x084510c0,
+ 0x04880402, 0x21240808,
+ 0x49410650, 0x02906030, 0x00a01069, 0xc1040200, 0x00014116, 0x2420c024,
+ 0x02488008, 0x00420182,
+ 0x00340261, 0x11603200, 0xa2190420, 0x48804304, 0x00009401, 0x12002432,
+ 0x21804808, 0xc3291080,
+ 0x104845a0, 0x44041020, 0x1009a202, 0xb0420100, 0x20124840, 0x08040018,
+ 0x00810404, 0x21900208,
+ 0x0948205a, 0x264000b4, 0x6004000c, 0x08202489, 0xa0800d12, 0x08261244,
+ 0x88290200, 0x20902504,
+ 0x08b49124, 0x0308040a, 0x14424012, 0x20000800, 0x13040088, 0x14032404,
+ 0x21008a00, 0x10050242,
+ 0x04410080, 0x09124100, 0x50202002, 0x02084820, 0x08201148, 0x08401610,
+ 0x02002194, 0x4080802c,
+ 0x9004a408, 0x00024190, 0x00225221, 0x50083600, 0x80402422, 0x64a44041,
+ 0x81000000, 0x82580802,
+ 0x08148209, 0x02042049, 0x80114122, 0x0c80100c, 0x48408090, 0x20804530,
+ 0x08228160, 0xd1010002,
+ 0x90882004, 0x21009024, 0x0a001618, 0x021100a2, 0x44844901, 0x88401082,
+ 0xa0100082, 0x00024020,
+ 0x58200489, 0x00992c32, 0x20804804, 0xc0608482, 0x00480430, 0x0092004d,
+ 0x93010409, 0x04034102,
+ 0x24100004, 0x120c0010, 0x800101a4, 0x00048008, 0x882500c2, 0x02004c00,
+ 0x6000430c, 0x40409000,
+ 0x02980802, 0x25065a00, 0x014894c1, 0x22100014, 0x48960060, 0x5100a040,
+ 0x84820900, 0x04001061,
+ 0x11080601, 0x96000002, 0x60004308, 0x19090000, 0x204044a0, 0x28028120,
+ 0x52413043, 0x26890530,
+ 0x09044840, 0x0a0104c0, 0x101200a4, 0x48220045, 0x01008202, 0x00096880,
+ 0x00200205, 0x12409099,
+ 0x10420c84, 0x44840201, 0x01011240, 0x22410c34, 0x20108021, 0xc0009400,
+ 0xa0104122, 0x01064008,
+ 0xc8201200, 0x10102000, 0x0c941028, 0x1004a000, 0x30024004, 0x04104020,
+ 0x1a04a498, 0x12120880,
+ 0x61208041, 0x01490200, 0x06004012, 0x00805001, 0x8220b003, 0x80806810,
+ 0x09240000, 0x09488242,
+ 0x22120004, 0x0c208900, 0x40208613, 0x90022900, 0x48120004, 0x010c2410,
+ 0x04d10180, 0x45000a68,
+ 0x002512c2, 0x200a4c10, 0x0002d100, 0x8a200000, 0x16102c00, 0x04804240,
+ 0x01489010, 0x20d80104,
+ 0x04801804, 0x810c0008, 0x00010110, 0x04221200, 0x59003009, 0x06010922,
+ 0x64204060, 0x90280210,
+ 0x82580002, 0x29948205, 0x18243080, 0x14904100, 0x29800b00, 0x08219011,
+ 0x02400024, 0x00200069,
+ 0xc001a251, 0x04020014, 0x20320260, 0x42049418, 0x10c02822, 0x60004901,
+ 0x11443008, 0x00004004,
+ 0x4182420c, 0x9040804b, 0x22800102, 0x28804244, 0xc3289010, 0x004a25a0,
+ 0x08840040, 0x402c2610,
+ 0x90030182, 0x04028044, 0x00480291, 0x04c10020, 0x00000028, 0x106120d0,
+ 0x040b0004, 0x68109320,
+ 0xc8408448, 0x22010020, 0x05060804, 0x024804c3, 0x02506400, 0x44901804,
+ 0x11088042, 0x04002016,
+ 0x2400d801, 0x10048081, 0x00020182, 0x21300140, 0x08251098, 0x800104a2,
+ 0x09001200, 0x524010c1,
+ 0x82010810, 0x0c205048, 0x83010002, 0x028004b4, 0x0000812c, 0x00002400,
+ 0x10490180, 0x64009a00,
+ 0x18042410, 0x90402104, 0x00b44848, 0x81092002, 0x84090030, 0x08805000,
+ 0x02241082, 0x86004912,
+ 0x00024200, 0x4b090080, 0x20d000a0, 0x44141144, 0x40212200, 0x008a0912,
+ 0x0d304821, 0x08408208,
+ 0x94830424, 0x01200141, 0x88403212, 0x20084002, 0x21040101, 0x100480c2,
+ 0xb0002802, 0x09a01808,
+ 0x80408201, 0x22900404, 0x48308825, 0x81040613, 0x30004890, 0x01000201,
+ 0x03040600, 0x84422404,
+ 0x40000108, 0x102d0052, 0x02024400, 0x00048001, 0x0a24840a, 0x82006410,
+ 0x2ca05048, 0x08090040,
+ 0x32c04000, 0x00020000, 0x800ca040, 0x30420190, 0x0d120260, 0x40403089,
+ 0x04820104, 0x04100921,
+ 0x9048021a, 0x80500080, 0x48840005, 0x1a012049, 0xb0884420, 0x2000010c,
+ 0x40601282, 0x10820434,
+ 0x00021140, 0x42008650, 0x04002090, 0x45100045, 0x02442400, 0x04410882,
+ 0x2484c320, 0x88002052,
+ 0x02510080, 0x40064028, 0xd0412400, 0xa0890c00, 0x20a40200, 0x00009200,
+ 0x000a4400, 0x00b40001,
+ 0x11250410, 0x80404184, 0x61008244, 0x1a000000, 0x14410002, 0x25208101,
+ 0x814102c8, 0x82124004,
+ 0x49008020, 0x0a009440, 0x26102800, 0x21825808, 0x824810d2, 0x22000100,
+ 0x04320024, 0x10210003,
+ 0x00c90104, 0x28100025, 0x11481299, 0x84000482, 0x0090c008, 0x19000288,
+ 0x044a4404, 0x60869204,
+ 0x1005a040, 0x02090c20, 0x08201100, 0x41608293, 0x12180080, 0x04209101,
+ 0x800d2412, 0x14096912,
+ 0x20020021, 0x01002098, 0x92100980, 0x44844268, 0x00290240, 0x00520c22,
+ 0x48900300, 0x10210488,
+ 0x14182012, 0x20204200, 0x82080440, 0x20020404, 0x0c801104, 0x40000001,
+ 0x90810116, 0x20104800,
+ 0x1a000600, 0x80902c24, 0x40100221, 0x8048000a, 0x000008b6, 0x01801020,
+ 0x98442008, 0x32802502,
+ 0x0c041208, 0x40019442, 0x20582110, 0x0cb48800, 0x40000002, 0x80026102,
+ 0x00028000, 0x4b041291,
+ 0x00110102, 0x00948868, 0x08043050, 0x220b0082, 0x01140108, 0x42202441,
+ 0x14114810, 0x20000240,
+ 0xc0001202, 0x30080194, 0x40800024, 0x10288050, 0x80806886, 0x49021020,
+ 0x49080000, 0x82822100,
+ 0x40204300, 0x90291008, 0x24080010, 0x68000105, 0x40242089, 0xa4000002,
+ 0x00021104, 0x08218012,
+ 0x22000530, 0x04161009, 0xc2002210, 0x84032004, 0x40200060, 0x094c0010,
+ 0x10510824, 0x60244200,
+ 0x09481008, 0x00414c04, 0x01825005, 0x00619400, 0x02082122, 0x00200204,
+ 0x80080280, 0x02400190,
+ 0x08348944, 0x02040200, 0xa4420102, 0x0c100224, 0x18403201, 0x00010084,
+ 0x04248929, 0x08442090,
+ 0x801a0424, 0x6802c300, 0xc2418000, 0x20812010, 0x20244008, 0x00289051,
+ 0x00802480, 0x0c201048,
+ 0x91012001, 0x04402002, 0x0c100841, 0x41008280, 0x82002c20, 0x0094c840,
+ 0x11003250, 0x005100a0,
+ 0x0006820c, 0x4a403000, 0x06884130, 0x09061840, 0x09000010, 0x10906020,
+ 0x0820812c, 0x0101a240,
+ 0x14c80982, 0x60220004, 0x13001080, 0x80c00d00, 0x05100a09, 0x9900100a,
+ 0x20000430, 0x40049021,
+ 0x40408083, 0x34002130, 0x21044148, 0xc0010240, 0x00020584, 0x0000004c
+};
+
+#endif /* include guard */
diff --git a/lib/libmpa/mpa_primetest.c b/lib/libmpa/mpa_primetest.c
new file mode 100644
index 0000000..f8d67fa
--- /dev/null
+++ b/lib/libmpa/mpa_primetest.c
@@ -0,0 +1,291 @@
+/*
+ * 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"
+
+#define USE_PRIME_TABLE
+
+#if defined(USE_PRIME_TABLE)
+#include "mpa_primetable.h"
+#endif
+
+#define DEF_COMPOSITE 0
+#define DEF_PRIME 1
+#define PROB_PRIME -1
+
+/* Product of all primes < 1000 */
+static const mpa_num_base const_small_prime_factors = {
+ 44,
+ 44,
+ {0x2ED42696, 0x2BBFA177, 0x4820594F, 0xF73F4841,
+ 0xBFAC313A, 0xCAC3EB81, 0xF6F26BF8, 0x7FAB5061,
+ 0x59746FB7, 0xF71377F6, 0x3B19855B, 0xCBD03132,
+ 0xBB92EF1B, 0x3AC3152C, 0xE87C8273, 0xC0AE0E69,
+ 0x74A9E295, 0x448CCE86, 0x63CA1907, 0x8A0BF944,
+ 0xF8CC3BE0, 0xC26F0AF5, 0xC501C02F, 0x6579441A,
+ 0xD1099CDA, 0x6BC76A00, 0xC81A3228, 0xBFB1AB25,
+ 0x70FA3841, 0x51B3D076, 0xCC2359ED, 0xD9EE0769,
+ 0x75E47AF0, 0xD45FF31E, 0x52CCE4F6, 0x04DBC891,
+ 0x96658ED2, 0x1753EFE5, 0x3AE4A5A6, 0x8FD4A97F,
+ 0x8B15E7EB, 0x0243C3E1, 0xE0F0C31D, 0x0000000B}
+};
+
+/*
+ * If n is less than this number (341550071728321 decimal) the Miller-Rabin
+ * test (using specific bases) constitutes a primality proof.
+ */
+static const mpa_num_base const_miller_rabin_proof_limit = {
+ 2,
+ 2,
+ {0x52B2C8C1, 0x000136A3}
+};
+
+static const mpa_num_base const_two = {
+ 1,
+ 1,
+ {0x00000002}
+};
+
+/* foward declarations */
+static int is_small_prime(mpanum n);
+static int has_small_factors(mpanum n, mpa_scratch_mem pool);
+static int primality_test_miller_rabin(mpanum n, int conf_level,
+ mpa_scratch_mem pool);
+
+/*------------------------------------------------------------
+ *
+ * mpa_is_prob_prime
+ *
+ * Returns:
+ * 0 if n is definitely composite
+ * 1 if n is definitely prime
+ * -1 if n is composite with a probability less than 2^(-conf_level)
+ *
+ */
+int mpa_is_prob_prime(mpanum n, int conf_level, mpa_scratch_mem pool)
+{
+ int result = 0;
+
+ /* Check if it's a small prime */
+ result = is_small_prime(n);
+ if (result != PROB_PRIME)
+ goto cleanup;
+
+ /* Test if n is divisible by any prime < 1000 */
+ if (has_small_factors(n, pool)) {
+ result = DEF_COMPOSITE;
+ goto cleanup;
+ }
+ /* Check with Miller Rabin */
+ result = primality_test_miller_rabin(n, conf_level, pool);
+
+cleanup:
+ return result;
+}
+
+#if defined(USE_PRIME_TABLE)
+/*------------------------------------------------------------
+ *
+ * check_table
+ *
+ */
+static uint32_t check_table(uint32_t v)
+{
+ return (PRIME_TABLE[v >> 5] >> (v & 0x1f)) & 1;
+}
+#endif
+
+/*------------------------------------------------------------
+ *
+ * is_small_prime
+ *
+ * Returns 1 if n is prime,
+ Returns 0 if n is composite
+ * Returns -1 if we cannot decide
+ *
+ */
+static int is_small_prime(mpanum n)
+{
+ mpa_word_t v;
+
+ /* If n is larger than a mpa_word_t, we can only decide if */
+ /* n is even. If it's odd we cannot tell. */
+ if (__mpanum_size(n) > 1)
+ return ((mpa_parity(n) == MPA_EVEN_PARITY) ? 0 : -1);
+
+ v = mpa_get_word(n); /* will convert negative n:s to positive v:s. */
+ if ((v | 1) == 1) /* 0 and 1 are not prime */
+ return DEF_COMPOSITE;
+ if (v == 2) /* 2 is prime */
+ return DEF_PRIME;
+ if ((v & 1) == 0)
+ return DEF_COMPOSITE; /* but no other even number */
+
+#if defined(USE_PRIME_TABLE)
+ if (mpa_cmp_short(n, MAX_TABULATED_PRIME) > 0)
+ return -1;
+ v = (v - 3) >> 1;
+ return check_table(v);
+#else
+ return -1;
+#endif
+}
+
+/*------------------------------------------------------------
+ *
+ * has_small_factors
+ *
+ * returns 1 if n has small factors
+ * returns 0 if not.
+ */
+static int has_small_factors(mpanum n, mpa_scratch_mem pool)
+{
+ const mpa_num_base *factors = &const_small_prime_factors;
+ int result;
+ mpanum res;
+
+ mpa_alloc_static_temp_var(&res, pool);
+ mpa_gcd(res, n, (const mpanum)factors, pool);
+ result = (mpa_cmp_short(res, 1) == 0) ? 0 : 1;
+ mpa_free_static_temp_var(&res, pool);
+
+ return result;
+}
+
+/*------------------------------------------------------------
+ *
+ * primality_test_miller_rabin
+ *
+ */
+static int primality_test_miller_rabin(mpanum n, int conf_level,
+ mpa_scratch_mem pool)
+{
+ int result;
+ bool proof_version;
+ static const int32_t proof_a[7] = { 2, 3, 5, 7, 11, 13, 17 };
+ int cnt;
+ int idx;
+ int t;
+ int e = 0;
+ int cmp_one;
+ mpanum a;
+ mpanum q;
+ mpanum n_minus_1;
+ mpanum b;
+ mpanum r_modn;
+ mpanum r2_modn;
+ mpa_word_t n_inv;
+
+ mpa_alloc_static_temp_var(&r_modn, pool);
+ mpa_alloc_static_temp_var(&r2_modn, pool);
+
+ if (mpa_compute_fmm_context(n, r_modn, r2_modn, &n_inv, pool) == -1) {
+ result = DEF_COMPOSITE;
+ goto cleanup_short;
+ }
+
+ mpa_alloc_static_temp_var(&a, pool);
+ mpa_alloc_static_temp_var(&q, pool);
+ mpa_alloc_static_temp_var(&n_minus_1, pool);
+ mpa_alloc_static_temp_var(&b, pool);
+
+ proof_version =
+ (mpa_cmp(n, (mpanum) &const_miller_rabin_proof_limit) < 0);
+
+ if (proof_version)
+ cnt = 7;
+ else /* MR has 1/4 chance in failing a composite */
+ cnt = (conf_level + 1) / 2;
+
+ mpa_sub_word(n_minus_1, n, 1, pool);
+ mpa_set(q, n_minus_1);
+ t = 0;
+ /* calculate q such that n - 1 = 2^t * q where q is odd */
+ while (mpa_is_even(q)) {
+ mpa_shift_right(q, q, 1);
+ t++;
+ }
+
+ result = PROB_PRIME;
+ for (idx = 0; idx < cnt && result == PROB_PRIME; idx++) {
+ if (proof_version) {
+ mpa_set_S32(a, proof_a[idx]);
+ if (mpa_cmp(n, a) == 0) {
+ result = DEF_PRIME;
+ continue;
+ }
+ } else {
+ /*
+ * Get random a, 1 < a < N by
+ * asking for a random in range 0 <= x < N - 2
+ * and then add 2 to it.
+ */
+ mpa_sub_word(n_minus_1, n_minus_1, 1, pool);
+ /* n_minus_1 is now N - 2 ! */
+ mpa_get_random(a, n_minus_1);
+ mpa_add_word(n_minus_1, n_minus_1, 1, pool);
+ /* and a is now 2 <= a < N */
+ mpa_add_word(a, a, 2, pool);
+ }
+
+ mpa_exp_mod(b, a, q, n, r_modn, r2_modn, n_inv, pool);
+ e = 0;
+
+inner_loop:
+ cmp_one = mpa_cmp_short(b, 1);
+ if ((cmp_one == 0) && (e > 0)) {
+ result = DEF_COMPOSITE;
+ continue;
+ }
+
+ if ((mpa_cmp(b, n_minus_1) == 0) ||
+ ((cmp_one == 0) && (e == 0))) {
+ /* probably prime, try another a */
+ continue;
+ }
+
+ e++;
+ if (e < t) {
+ mpa_exp_mod(b, b, (mpanum) &const_two, n, r_modn,
+ r2_modn, n_inv, pool);
+ goto inner_loop;
+ }
+ result = DEF_COMPOSITE;
+ }
+
+ if (result == PROB_PRIME && proof_version)
+ result = DEF_PRIME;
+
+ mpa_free_static_temp_var(&a, pool);
+ mpa_free_static_temp_var(&q, pool);
+ mpa_free_static_temp_var(&n_minus_1, pool);
+ mpa_free_static_temp_var(&b, pool);
+cleanup_short:
+ mpa_free_static_temp_var(&r_modn, pool);
+ mpa_free_static_temp_var(&r2_modn, pool);
+
+ return result;
+}
diff --git a/lib/libmpa/mpa_random.c b/lib/libmpa/mpa_random.c
new file mode 100644
index 0000000..2ee0031
--- /dev/null
+++ b/lib/libmpa/mpa_random.c
@@ -0,0 +1,81 @@
+/*
+ * 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"
+#include <tee_api_types.h>
+
+static random_generator_cb get_rng_array;
+
+void mpa_set_random_generator(random_generator_cb callback)
+{
+ get_rng_array = callback;
+}
+
+static uint8_t get_random_byte(void)
+{
+ uint8_t buf;
+ while (get_rng_array(&buf, 1) != TEE_SUCCESS)
+ ;
+
+ return buf;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_get_random
+ *
+ */
+void mpa_get_random(mpanum dest, mpanum limit)
+{
+ int done = 0;
+
+ mpa_wipe(dest);
+ if (__mpanum_alloced(dest) < __mpanum_size(limit))
+ dest->size = __mpanum_alloced(dest);
+ else
+ dest->size = __mpanum_size(limit);
+ while (!done) {
+ for (int idx = 0; idx < dest->size; idx++) {
+ mpa_word_t w = 0;
+ for (int j = 0; j < BYTES_PER_WORD; j++)
+ w = (w << 8) ^ get_random_byte();
+ dest->d[idx] = w;
+ }
+ if (dest->size < __mpanum_size(limit)) {
+ done = 1;
+ } else {
+ mpa_word_t hbi =
+ (mpa_word_t) mpa_highest_bit_index(limit);
+ /* 1 <= hbi <= WORD_SIZE */
+ hbi = (hbi % WORD_SIZE) + 1;
+ if (hbi < WORD_SIZE) {
+ hbi = (1 << hbi) - 1;
+ dest->d[dest->size - 1] &= hbi;
+ }
+ done = (mpa_cmp(dest, limit) < 0) ? 1 : 0;
+ }
+ }
+}
diff --git a/lib/libmpa/mpa_shift.c b/lib/libmpa/mpa_shift.c
new file mode 100644
index 0000000..0d64910
--- /dev/null
+++ b/lib/libmpa/mpa_shift.c
@@ -0,0 +1,237 @@
+/*
+ * 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"
+
+/*************************************************************
+ *
+ * HELPER FUNCTIONS
+ *
+ *************************************************************/
+
+/*------------------------------------------------------------
+ *
+ * __mpa_shift_words_left
+ *
+ */
+void __mpa_shift_words_left(mpanum op, mpa_word_t q)
+{
+ mpa_word_t i;
+
+ if (q == 0 || __mpanum_is_zero(op))
+ return;
+ for (i = __mpanum_size(op) + q - 1; i > q - 1; i--)
+ op->d[i] = op->d[i - q];
+
+ mpa_memset(op->d, 0, BYTES_PER_WORD * q);
+
+ /* update the size of op */
+ if (op->size > 0)
+ op->size += q;
+ else
+ op->size -= q;
+}
+
+/*------------------------------------------------------------
+ *
+ * __mpa_shift_words_right
+ *
+ */
+void __mpa_shift_words_right(mpanum op, mpa_word_t q)
+{
+ mpa_word_t i;
+
+ if (q == 0 || __mpanum_is_zero(op))
+ return;
+
+ if (q >= __mpanum_size(op)) {
+ mpa_set_word(op, 0);
+ return;
+ }
+
+ for (i = 0; i < __mpanum_size(op) - q; i++)
+ op->d[i] = op->d[i + q];
+
+ /* update the size of dest */
+ if (op->size > 0)
+ op->size -= q;
+ else
+ op->size += q;
+}
+
+/*************************************************************
+ *
+ * LIB FUNCTIONS
+ *
+ *************************************************************/
+
+/* --------------------------------------------------------------------
+ * mpa_shift_left
+ *
+ * Shifts src left by "steps" step and put result in dest.
+ * It does not care about signs. Dest will have same sign as src.
+ */
+void mpa_shift_left(mpanum dest, mpanum src, mpa_word_t steps)
+{
+ mpa_word_t q; /* quotient of steps div WORD_SIZE */
+ mpa_word_t r; /* remainder of steps div WORD_SIZE */
+ mpa_word_t i;
+ /* the bits of the word which will be shifted into another word */
+ mpa_word_t rbits;
+ mpa_word_t need_extra_word;
+
+ /*
+ * Copy first, then check, since even a shifted zero should
+ * be copied.
+ */
+ mpa_copy(dest, src);
+ __mpa_set_unused_digits_to_zero(dest);
+ if (steps == 0 || __mpanum_is_zero(dest))
+ return;
+
+ r = steps & (WORD_SIZE - 1); /* 0 <= r < WORD_SIZE */
+ q = steps >> LOG_OF_WORD_SIZE; /* 0 <= q */
+
+ /*
+ * The size of dest will always increase by at least q.
+ * If we're shifting r bits and the r highest bits in
+ * the MSW of dest is zero, we don't need the extra word
+ * Note:
+ * We cannot do
+ * if (_mpanumMSW(dest) >> (WORD_SIZE - r))
+ * since some compilers (MS) does not shift the word
+ * if the shift quantity is larger or equal to the word size...
+ * Otherwise it would be natural to say that (a >> b) is just zero
+ * if b is larger than the number of bit of a, but no no...
+ */
+ need_extra_word = 0;
+
+ if (r == 0) { /* and q > 0 */
+ /*
+ * We have a simple shift by words
+ */
+ for (i = __mpanum_size(dest) + q - 1; i > q - 1; i--)
+ dest->d[i] = dest->d[i - q];
+ } else {
+ if (__mpanum_msw(dest) &
+ (((((mpa_word_t)1 << r) - 1u)) << (WORD_SIZE - r)))
+ need_extra_word = 1;
+ /*
+ * We have a combination of word and bit shifting.
+ *
+ * If need_extra_word is 1, the MSW is special and handled
+ * here
+ */
+ i = __mpanum_size(dest) + q + need_extra_word;
+ if (need_extra_word) {
+ rbits = dest->d[i - q - 1] >> (WORD_SIZE - r);
+ dest->d[i] ^= rbits;
+ }
+ i--;
+ dest->d[i] = dest->d[i - q] << r;
+ while (i > q) {
+ rbits = dest->d[i - q - 1] >> (WORD_SIZE - r);
+ dest->d[i] ^= rbits;
+ i--;
+ dest->d[i] = dest->d[i - q] << r;
+ }
+ }
+ mpa_memset(dest->d, 0, BYTES_PER_WORD * q);
+ /* update the size of dest */
+ if (dest->size > 0)
+ dest->size += q + need_extra_word;
+ else
+ dest->size -= q + need_extra_word;
+}
+
+/*------------------------------------------------------------
+ *
+ * mpa_shift_right
+ *
+ * Shifts src right by "steps" step and put result in dest.
+ * It does not care about signs. Dest will have same sign as src.
+ *
+ */
+void mpa_shift_right(mpanum dest, mpanum src, mpa_word_t steps)
+{
+ mpa_word_t q; /* quotient of steps div WORD_SIZE */
+ mpa_word_t r; /* remainder of steps div WORD_SIZE */
+ mpa_word_t i;
+ /* the bits of the word which will be shifted into another word */
+ mpa_word_t rbits;
+
+ /*
+ * Copy first, then check, since even a shifted zero should
+ * be copied.
+ */
+ mpa_copy(dest, src);
+ __mpa_set_unused_digits_to_zero(dest);
+ if (steps == 0 || __mpanum_is_zero(dest))
+ return;
+
+ r = steps & (WORD_SIZE - 1); /* 0 <= r < WORD_SIZE */
+ q = steps >> LOG_OF_WORD_SIZE; /* 0 <= q */
+
+ if (q >= __mpanum_size(dest)) {
+ mpa_set_word(dest, 0);
+ return;
+ }
+
+ /*
+ * Here we have:
+ * 0 <= r < WORD_SIZE - 1
+ * 0 <= q < _mpanumSize(dest)
+ */
+ if (r == 0) { /* and q > 0 */
+ /* Simple shift by words */
+ for (i = 0; i < __mpanum_size(dest) - q; i++)
+ dest->d[i] = dest->d[i + q];
+ } else {
+ /* combination of word and bit shifting */
+ for (i = 0; i < __mpanum_size(dest) - q - 1; i++) {
+ dest->d[i] = dest->d[i + q];
+ rbits = dest->d[i + q + 1] & ((1UL << r) - 1);
+ dest->d[i] =
+ (dest->d[i] >> r) ^ (rbits << (WORD_SIZE - r));
+ }
+ /* final word is special */
+ dest->d[i] = dest->d[i + q] >> r;
+ }
+
+ /* update the size of dest */
+ if (dest->size > 0)
+ dest->size -= q;
+ else
+ dest->size += q;
+
+ /* Take care of the case when we shifted out all bits from MSW */
+ if (__mpanum_msw(dest) == 0) {
+ if (dest->size > 0)
+ dest->size--;
+ else
+ dest->size++;
+ }
+}
diff --git a/lib/libmpa/sub.mk b/lib/libmpa/sub.mk
new file mode 100644
index 0000000..38c1610
--- /dev/null
+++ b/lib/libmpa/sub.mk
@@ -0,0 +1,45 @@
+global-incdirs-y += include
+
+ifneq ($(sm),core) # User-mode
+cflags-lib-$(CFG_ULIBS_GPROF) += -pg
+endif
+
+srcs-y += mpa_misc.c
+cflags-remove-mpa_misc.c-y += -pedantic
+cflags-mpa_misc.c-y += -Wno-sign-compare
+
+srcs-y += mpa_montgomery.c
+cflags-remove-mpa_montgomery.c-y += -Wdeclaration-after-statement
+
+srcs-y += mpa_primetest.c
+cflags-remove-mpa_primetest.c-y += -pedantic
+
+srcs-y += mpa_conv.c
+cflags-mpa_conv.c-y += -Wno-sign-compare
+
+srcs-y += mpa_div.c
+cflags-mpa_div.c-y += -Wno-sign-compare
+
+srcs-y += mpa_gcd.c
+cflags-mpa_gcd.c-y += -Wno-sign-compare
+
+srcs-y += mpa_mem_static.c
+cflags-mpa_mem_static.c-y += -Wno-sign-compare
+
+srcs-y += mpa_mul.c
+cflags-mpa_mul.c-y += -Wno-sign-compare
+
+srcs-y += mpa_random.c
+cflags-mpa_random.c-y += -Wno-sign-compare
+
+srcs-y += mpa_shift.c
+cflags-mpa_shift.c-y += -Wno-sign-compare
+
+srcs-y += mpa_addsub.c
+srcs-y += mpa_cmp.c
+srcs-y += mpa_expmod.c
+srcs-y += mpa_init.c
+srcs-y += mpa_io.c
+srcs-y += mpa_modulus.c
+
+subdirs-$(arch_arm) += arch/$(ARCH)