xref: /optee_os/lib/libutee/tee_api_arith_mpi.c (revision 98efc118f400621401ff981d176e0aedd720fbd3)
1062e3d01SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2062e3d01SJens Wiklander /*
3062e3d01SJens Wiklander  * Copyright (c) 2018, Linaro limited
4062e3d01SJens Wiklander  */
5062e3d01SJens Wiklander #include <assert.h>
6062e3d01SJens Wiklander #include <mbedtls/bignum.h>
7062e3d01SJens Wiklander #include <mempool.h>
8062e3d01SJens Wiklander #include <stdio.h>
9062e3d01SJens Wiklander #include <string.h>
10062e3d01SJens Wiklander #include <tee_api.h>
11062e3d01SJens Wiklander #include <tee_arith_internal.h>
12062e3d01SJens Wiklander #include <utee_defines.h>
13062e3d01SJens Wiklander #include <utee_syscalls.h>
14062e3d01SJens Wiklander #include <util.h>
15062e3d01SJens Wiklander 
16062e3d01SJens Wiklander #define MPI_MEMPOOL_SIZE	(8 * 1024)
17062e3d01SJens Wiklander 
18062e3d01SJens Wiklander static void __noreturn api_panic(const char *func, int line, const char *msg)
19062e3d01SJens Wiklander {
20062e3d01SJens Wiklander 	printf("Panic function %s, line %d: %s\n", func, line, msg);
21062e3d01SJens Wiklander 	TEE_Panic(0xB16127 /*BIGINT*/);
22062e3d01SJens Wiklander 	while (1)
23062e3d01SJens Wiklander 		; /* Panic will crash the thread */
24062e3d01SJens Wiklander }
25062e3d01SJens Wiklander 
26062e3d01SJens Wiklander #define API_PANIC(x) api_panic(__func__, __LINE__, x)
27062e3d01SJens Wiklander 
28062e3d01SJens Wiklander static void __noreturn mpi_panic(const char *func, int line, int rc)
29062e3d01SJens Wiklander {
30062e3d01SJens Wiklander 	printf("Panic function %s, line %d, code %d\n", func, line, rc);
31062e3d01SJens Wiklander 	TEE_Panic(0xB16127 /*BIGINT*/);
32062e3d01SJens Wiklander 	while (1)
33062e3d01SJens Wiklander 		; /* Panic will crash the thread */
34062e3d01SJens Wiklander }
35062e3d01SJens Wiklander 
36062e3d01SJens Wiklander #define MPI_CHECK(x) do { \
37062e3d01SJens Wiklander 		int _rc = (x); \
38062e3d01SJens Wiklander 		 \
39062e3d01SJens Wiklander 		if (_rc) \
40062e3d01SJens Wiklander 			mpi_panic(__func__, __LINE__, _rc); \
41062e3d01SJens Wiklander 	} while (0)
42062e3d01SJens Wiklander 
43062e3d01SJens Wiklander void _TEE_MathAPI_Init(void)
44062e3d01SJens Wiklander {
45062e3d01SJens Wiklander 	static uint8_t data[MPI_MEMPOOL_SIZE]
46062e3d01SJens Wiklander 		__aligned(__alignof__(mbedtls_mpi_uint));
47062e3d01SJens Wiklander 
48062e3d01SJens Wiklander 	mbedtls_mpi_mempool = mempool_alloc_pool(data, sizeof(data), NULL);
49062e3d01SJens Wiklander 	if (!mbedtls_mpi_mempool)
50062e3d01SJens Wiklander 		API_PANIC("Failed to initialize memory pool");
51062e3d01SJens Wiklander }
52062e3d01SJens Wiklander 
53062e3d01SJens Wiklander struct bigint_hdr {
54062e3d01SJens Wiklander 	int32_t sign;
55062e3d01SJens Wiklander 	uint16_t alloc_size;
56062e3d01SJens Wiklander 	uint16_t nblimbs;
57062e3d01SJens Wiklander };
58062e3d01SJens Wiklander 
59062e3d01SJens Wiklander #define BIGINT_HDR_SIZE_IN_U32	2
60062e3d01SJens Wiklander 
61062e3d01SJens Wiklander static void init_static_mpi(mbedtls_mpi *mpi, TEE_BigInt *bigInt)
62062e3d01SJens Wiklander {
63062e3d01SJens Wiklander 	struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt;
64062e3d01SJens Wiklander 
65062e3d01SJens Wiklander 	mbedtls_mpi_init_static(mpi, (mbedtls_mpi_uint *)(hdr + 1),
66062e3d01SJens Wiklander 				hdr->sign, hdr->alloc_size, hdr->nblimbs);
67062e3d01SJens Wiklander }
68062e3d01SJens Wiklander 
69062e3d01SJens Wiklander /*
70062e3d01SJens Wiklander  * Initializes a MPI.
71062e3d01SJens Wiklander  *
72062e3d01SJens Wiklander  * If a bigint is supplied it's initialized with the value of the bigint
73062e3d01SJens Wiklander  * and changes will be written back completely with a call to put_mpi().
74062e3d01SJens Wiklander  * The bigint dictates the size of the MPI which will be fixed to this
75062e3d01SJens Wiklander  * size.
76062e3d01SJens Wiklander  *
77062e3d01SJens Wiklander  * If no bigint is supplied a temporary MPI is allocated instead which will
78062e3d01SJens Wiklander  * be freed by put_mpi().
79062e3d01SJens Wiklander  */
80062e3d01SJens Wiklander static void get_mpi(mbedtls_mpi *mpi, TEE_BigInt *bigInt)
81062e3d01SJens Wiklander {
82062e3d01SJens Wiklander 	/*
83062e3d01SJens Wiklander 	 * The way the GP spec is defining the bignums it's
84062e3d01SJens Wiklander 	 * difficult/tricky to do it using 64-bit arithmetics given that
85062e3d01SJens Wiklander 	 * we'd need 64-bit alignment of the data as well.
86062e3d01SJens Wiklander 	 */
87062e3d01SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(mbedtls_mpi_uint) == sizeof(uint32_t));
88062e3d01SJens Wiklander 
89062e3d01SJens Wiklander 	/*
90062e3d01SJens Wiklander 	 * The struct bigint_hdr is the overhead added to the bigint and
91062e3d01SJens Wiklander 	 * is required to take exactly 2 uint32_t.
92062e3d01SJens Wiklander 	 */
93062e3d01SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(struct bigint_hdr) ==
94062e3d01SJens Wiklander 			    sizeof(uint32_t) * BIGINT_HDR_SIZE_IN_U32);
95062e3d01SJens Wiklander 
96062e3d01SJens Wiklander 	if (bigInt)
97062e3d01SJens Wiklander 		init_static_mpi(mpi, bigInt);
98062e3d01SJens Wiklander 	else
99062e3d01SJens Wiklander 		mbedtls_mpi_init_mempool(mpi);
100062e3d01SJens Wiklander }
101062e3d01SJens Wiklander 
102062e3d01SJens Wiklander /*
103062e3d01SJens Wiklander  * Initializes a MPI from a constant bigint.
104062e3d01SJens Wiklander  *
105062e3d01SJens Wiklander  * A MPI is allocated and given an initial value based on the supplied
106062e3d01SJens Wiklander  * bigint. When the MPI is freed with put_mpi() no changes are propagated
107062e3d01SJens Wiklander  * back.
108062e3d01SJens Wiklander  */
109062e3d01SJens Wiklander static void get_const_mpi(mbedtls_mpi *mpi, const TEE_BigInt *bigInt)
110062e3d01SJens Wiklander {
111062e3d01SJens Wiklander 	mbedtls_mpi mpi_const;
112062e3d01SJens Wiklander 
113062e3d01SJens Wiklander 	init_static_mpi(&mpi_const, (TEE_BigInt *)bigInt);
114062e3d01SJens Wiklander 	get_mpi(mpi, NULL);
115062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(mpi, &mpi_const));
116062e3d01SJens Wiklander }
117062e3d01SJens Wiklander 
118062e3d01SJens Wiklander /*
119062e3d01SJens Wiklander  * Uninitialize a MPI.
120062e3d01SJens Wiklander  *
121062e3d01SJens Wiklander  * If the MPI is linked to a bigint the final changes (size and sign) will
122062e3d01SJens Wiklander  * be copied back.
123062e3d01SJens Wiklander  *
124062e3d01SJens Wiklander  * If the MPI isn't linked to bigint it's only freed.
125062e3d01SJens Wiklander  */
126062e3d01SJens Wiklander static void put_mpi(mbedtls_mpi *mpi)
127062e3d01SJens Wiklander {
128062e3d01SJens Wiklander 	if (mpi->alloc_type == MBEDTLS_MPI_ALLOC_TYPE_STATIC) {
129062e3d01SJens Wiklander 		struct bigint_hdr *hdr = ((struct bigint_hdr *)mpi->p) - 1;
130062e3d01SJens Wiklander 
131062e3d01SJens Wiklander 		hdr->sign = mpi->s;
132062e3d01SJens Wiklander 		hdr->nblimbs = mpi->n;
133062e3d01SJens Wiklander 	} else {
134062e3d01SJens Wiklander 		mbedtls_mpi_free(mpi);
135062e3d01SJens Wiklander 	}
136062e3d01SJens Wiklander }
137062e3d01SJens Wiklander 
138062e3d01SJens Wiklander void TEE_BigIntInit(TEE_BigInt *bigInt, uint32_t len)
139062e3d01SJens Wiklander {
140062e3d01SJens Wiklander 	memset(bigInt, 0, TEE_BigIntSizeInU32(len) * sizeof(uint32_t));
141062e3d01SJens Wiklander 
142062e3d01SJens Wiklander 	struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt;
143062e3d01SJens Wiklander 
144062e3d01SJens Wiklander 
145062e3d01SJens Wiklander 	hdr->sign = 1;
146062e3d01SJens Wiklander 	if ((len - BIGINT_HDR_SIZE_IN_U32) > MBEDTLS_MPI_MAX_LIMBS)
147062e3d01SJens Wiklander 		API_PANIC("Too large bigint");
148062e3d01SJens Wiklander 	hdr->alloc_size = len - BIGINT_HDR_SIZE_IN_U32;
149062e3d01SJens Wiklander }
150062e3d01SJens Wiklander 
151062e3d01SJens Wiklander TEE_Result TEE_BigIntConvertFromOctetString(TEE_BigInt *dest,
152062e3d01SJens Wiklander 					    const uint8_t *buffer,
153062e3d01SJens Wiklander 					    uint32_t bufferLen, int32_t sign)
154062e3d01SJens Wiklander {
155062e3d01SJens Wiklander 	TEE_Result res;
156062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
157062e3d01SJens Wiklander 
158062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
159062e3d01SJens Wiklander 
160062e3d01SJens Wiklander 	if (mbedtls_mpi_read_binary(&mpi_dest,  buffer, bufferLen))
161062e3d01SJens Wiklander 		res = TEE_ERROR_OVERFLOW;
162062e3d01SJens Wiklander 	else
163062e3d01SJens Wiklander 		res = TEE_SUCCESS;
164062e3d01SJens Wiklander 
165062e3d01SJens Wiklander 	if (sign < 0)
166062e3d01SJens Wiklander 		mpi_dest.s = -1;
167062e3d01SJens Wiklander 
168062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
169062e3d01SJens Wiklander 
170062e3d01SJens Wiklander 	return res;
171062e3d01SJens Wiklander }
172062e3d01SJens Wiklander 
173062e3d01SJens Wiklander TEE_Result TEE_BigIntConvertToOctetString(uint8_t *buffer, uint32_t *bufferLen,
174062e3d01SJens Wiklander 					  const TEE_BigInt *bigInt)
175062e3d01SJens Wiklander {
176062e3d01SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
177062e3d01SJens Wiklander 	mbedtls_mpi mpi;
178062e3d01SJens Wiklander 	size_t sz;
179062e3d01SJens Wiklander 
180062e3d01SJens Wiklander 	get_const_mpi(&mpi, bigInt);
181062e3d01SJens Wiklander 
182062e3d01SJens Wiklander 	sz = mbedtls_mpi_size(&mpi);
183062e3d01SJens Wiklander 	if (sz <= *bufferLen)
184062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_write_binary(&mpi, buffer, sz));
185062e3d01SJens Wiklander 	else
186062e3d01SJens Wiklander 		res = TEE_ERROR_SHORT_BUFFER;
187062e3d01SJens Wiklander 
188062e3d01SJens Wiklander 	*bufferLen = sz;
189062e3d01SJens Wiklander 
190062e3d01SJens Wiklander 	put_mpi(&mpi);
191062e3d01SJens Wiklander 
192062e3d01SJens Wiklander 	return res;
193062e3d01SJens Wiklander }
194062e3d01SJens Wiklander 
195062e3d01SJens Wiklander void TEE_BigIntConvertFromS32(TEE_BigInt *dest, int32_t shortVal)
196062e3d01SJens Wiklander {
197062e3d01SJens Wiklander 	mbedtls_mpi mpi;
198062e3d01SJens Wiklander 
199062e3d01SJens Wiklander 	get_mpi(&mpi, dest);
200062e3d01SJens Wiklander 
201062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&mpi, shortVal));
202062e3d01SJens Wiklander 
203062e3d01SJens Wiklander 	put_mpi(&mpi);
204062e3d01SJens Wiklander }
205062e3d01SJens Wiklander 
206062e3d01SJens Wiklander TEE_Result TEE_BigIntConvertToS32(int32_t *dest, const TEE_BigInt *src)
207062e3d01SJens Wiklander {
208062e3d01SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
209062e3d01SJens Wiklander 	mbedtls_mpi mpi;
210062e3d01SJens Wiklander 	uint32_t v;
211062e3d01SJens Wiklander 
212062e3d01SJens Wiklander 	get_const_mpi(&mpi, src);
213062e3d01SJens Wiklander 
214062e3d01SJens Wiklander 	if (mbedtls_mpi_write_binary(&mpi, (void *)&v, sizeof(v))) {
215062e3d01SJens Wiklander 		res = TEE_ERROR_OVERFLOW;
216062e3d01SJens Wiklander 		goto out;
217062e3d01SJens Wiklander 	}
218062e3d01SJens Wiklander 
219062e3d01SJens Wiklander 	if (mpi.s > 0) {
220062e3d01SJens Wiklander 		if (ADD_OVERFLOW(0, TEE_U32_FROM_BIG_ENDIAN(v), dest))
221062e3d01SJens Wiklander 			res = TEE_ERROR_OVERFLOW;
222062e3d01SJens Wiklander 	} else {
223062e3d01SJens Wiklander 		if (SUB_OVERFLOW(0, TEE_U32_FROM_BIG_ENDIAN(v), dest))
224062e3d01SJens Wiklander 			res = TEE_ERROR_OVERFLOW;
225062e3d01SJens Wiklander 	}
226062e3d01SJens Wiklander 
227062e3d01SJens Wiklander out:
228062e3d01SJens Wiklander 	put_mpi(&mpi);
229062e3d01SJens Wiklander 
230062e3d01SJens Wiklander 	return res;
231062e3d01SJens Wiklander }
232062e3d01SJens Wiklander 
233062e3d01SJens Wiklander int32_t TEE_BigIntCmp(const TEE_BigInt *op1, const TEE_BigInt *op2)
234062e3d01SJens Wiklander {
235062e3d01SJens Wiklander 	mbedtls_mpi mpi1;
236062e3d01SJens Wiklander 	mbedtls_mpi mpi2;
237062e3d01SJens Wiklander 	int32_t rc;
238062e3d01SJens Wiklander 
239062e3d01SJens Wiklander 	get_const_mpi(&mpi1, op1);
240062e3d01SJens Wiklander 	get_const_mpi(&mpi2, op2);
241062e3d01SJens Wiklander 
242062e3d01SJens Wiklander 	rc = mbedtls_mpi_cmp_mpi(&mpi1, &mpi2);
243062e3d01SJens Wiklander 
244062e3d01SJens Wiklander 	put_mpi(&mpi1);
245062e3d01SJens Wiklander 	put_mpi(&mpi2);
246062e3d01SJens Wiklander 
247062e3d01SJens Wiklander 	return rc;
248062e3d01SJens Wiklander }
249062e3d01SJens Wiklander 
250062e3d01SJens Wiklander int32_t TEE_BigIntCmpS32(const TEE_BigInt *op, int32_t shortVal)
251062e3d01SJens Wiklander {
252062e3d01SJens Wiklander 	mbedtls_mpi mpi;
253062e3d01SJens Wiklander 	int32_t rc;
254062e3d01SJens Wiklander 
255062e3d01SJens Wiklander 	get_const_mpi(&mpi, op);
256062e3d01SJens Wiklander 
257062e3d01SJens Wiklander 	rc = mbedtls_mpi_cmp_int(&mpi, shortVal);
258062e3d01SJens Wiklander 
259062e3d01SJens Wiklander 	put_mpi(&mpi);
260062e3d01SJens Wiklander 
261062e3d01SJens Wiklander 	return rc;
262062e3d01SJens Wiklander }
263062e3d01SJens Wiklander 
264062e3d01SJens Wiklander void TEE_BigIntShiftRight(TEE_BigInt *dest, const TEE_BigInt *op, size_t bits)
265062e3d01SJens Wiklander {
266062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
267062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
268062e3d01SJens Wiklander 
269062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
270062e3d01SJens Wiklander 
271062e3d01SJens Wiklander 	if (dest == op) {
272062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits));
273062e3d01SJens Wiklander 		goto out;
274062e3d01SJens Wiklander 	}
275062e3d01SJens Wiklander 
276062e3d01SJens Wiklander 	get_const_mpi(&mpi_op, op);
277062e3d01SJens Wiklander 
278062e3d01SJens Wiklander 	if (mbedtls_mpi_size(&mpi_dest) >= mbedtls_mpi_size(&mpi_op)) {
279062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_op));
280062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits));
281062e3d01SJens Wiklander 	} else {
282062e3d01SJens Wiklander 		mbedtls_mpi mpi_t;
283062e3d01SJens Wiklander 
284062e3d01SJens Wiklander 		get_mpi(&mpi_t, NULL);
285062e3d01SJens Wiklander 
286062e3d01SJens Wiklander 		/*
287062e3d01SJens Wiklander 		 * We're using a temporary buffer to avoid the corner case
288062e3d01SJens Wiklander 		 * where destination is unexpectedly overflowed by up to
289062e3d01SJens Wiklander 		 * @bits number of bits.
290062e3d01SJens Wiklander 		 */
291062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_t, &mpi_op));
292062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_t, bits));
293062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_t));
294062e3d01SJens Wiklander 
295062e3d01SJens Wiklander 		put_mpi(&mpi_t);
296062e3d01SJens Wiklander 	}
297062e3d01SJens Wiklander 
298062e3d01SJens Wiklander 	put_mpi(&mpi_op);
299062e3d01SJens Wiklander 
300062e3d01SJens Wiklander out:
301062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
302062e3d01SJens Wiklander }
303062e3d01SJens Wiklander 
304062e3d01SJens Wiklander bool TEE_BigIntGetBit(const TEE_BigInt *src, uint32_t bitIndex)
305062e3d01SJens Wiklander {
306062e3d01SJens Wiklander 	bool rc;
307062e3d01SJens Wiklander 	mbedtls_mpi mpi;
308062e3d01SJens Wiklander 
309062e3d01SJens Wiklander 	get_const_mpi(&mpi, src);
310062e3d01SJens Wiklander 
311062e3d01SJens Wiklander 	rc = mbedtls_mpi_get_bit(&mpi, bitIndex);
312062e3d01SJens Wiklander 
313062e3d01SJens Wiklander 	put_mpi(&mpi);
314062e3d01SJens Wiklander 
315062e3d01SJens Wiklander 	return rc;
316062e3d01SJens Wiklander }
317062e3d01SJens Wiklander 
318062e3d01SJens Wiklander uint32_t TEE_BigIntGetBitCount(const TEE_BigInt *src)
319062e3d01SJens Wiklander {
320062e3d01SJens Wiklander 	uint32_t rc;
321062e3d01SJens Wiklander 	mbedtls_mpi mpi;
322062e3d01SJens Wiklander 
323062e3d01SJens Wiklander 	get_const_mpi(&mpi, src);
324062e3d01SJens Wiklander 
325062e3d01SJens Wiklander 	rc = mbedtls_mpi_bitlen(&mpi);
326062e3d01SJens Wiklander 
327062e3d01SJens Wiklander 	put_mpi(&mpi);
328062e3d01SJens Wiklander 
329062e3d01SJens Wiklander 	return rc;
330062e3d01SJens Wiklander }
331062e3d01SJens Wiklander 
332062e3d01SJens Wiklander static void bigint_binary(TEE_BigInt *dest, const TEE_BigInt *op1,
333062e3d01SJens Wiklander 			  const TEE_BigInt *op2,
334062e3d01SJens Wiklander 			  int (*func)(mbedtls_mpi *X, const mbedtls_mpi *A,
335062e3d01SJens Wiklander 				      const mbedtls_mpi *B))
336062e3d01SJens Wiklander {
337062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
338062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
339062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
340062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
341062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
342062e3d01SJens Wiklander 
343062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
344062e3d01SJens Wiklander 
345062e3d01SJens Wiklander 	if (op1 == dest)
346062e3d01SJens Wiklander 		pop1 = &mpi_dest;
347062e3d01SJens Wiklander 	else
348062e3d01SJens Wiklander 		get_const_mpi(&mpi_op1, op1);
349062e3d01SJens Wiklander 
350062e3d01SJens Wiklander 	if (op2 == dest)
351062e3d01SJens Wiklander 		pop2 = &mpi_dest;
352062e3d01SJens Wiklander 	else if (op2 == op1)
353062e3d01SJens Wiklander 		pop2 = pop1;
354062e3d01SJens Wiklander 	else
355062e3d01SJens Wiklander 		get_const_mpi(&mpi_op2, op2);
356062e3d01SJens Wiklander 
357062e3d01SJens Wiklander 	MPI_CHECK(func(&mpi_dest, pop1, pop2));
358062e3d01SJens Wiklander 
359062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
360062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
361062e3d01SJens Wiklander 		put_mpi(&mpi_op1);
362062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
363062e3d01SJens Wiklander 		put_mpi(&mpi_op2);
364062e3d01SJens Wiklander }
365062e3d01SJens Wiklander 
366062e3d01SJens Wiklander static void bigint_binary_mod(TEE_BigInt *dest, const TEE_BigInt *op1,
367062e3d01SJens Wiklander 			      const TEE_BigInt *op2, const TEE_BigInt *n,
368062e3d01SJens Wiklander 			      int (*func)(mbedtls_mpi *X, const mbedtls_mpi *A,
369062e3d01SJens Wiklander 					  const mbedtls_mpi *B))
370062e3d01SJens Wiklander {
371062e3d01SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0)
372062e3d01SJens Wiklander 		API_PANIC("Modulus is too short");
373062e3d01SJens Wiklander 
374062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
375062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
376062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
377062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
378062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
379062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
380062e3d01SJens Wiklander 	mbedtls_mpi mpi_t;
381062e3d01SJens Wiklander 
382062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
383062e3d01SJens Wiklander 	get_const_mpi(&mpi_n, n);
384062e3d01SJens Wiklander 
385062e3d01SJens Wiklander 	if (op1 == dest)
386062e3d01SJens Wiklander 		pop1 = &mpi_dest;
387062e3d01SJens Wiklander 	else
388062e3d01SJens Wiklander 		get_const_mpi(&mpi_op1, op1);
389062e3d01SJens Wiklander 
390062e3d01SJens Wiklander 	if (op2 == dest)
391062e3d01SJens Wiklander 		pop2 = &mpi_dest;
392062e3d01SJens Wiklander 	else if (op2 == op1)
393062e3d01SJens Wiklander 		pop2 = pop1;
394062e3d01SJens Wiklander 	else
395062e3d01SJens Wiklander 		get_const_mpi(&mpi_op2, op2);
396062e3d01SJens Wiklander 
397062e3d01SJens Wiklander 	get_mpi(&mpi_t, NULL);
398062e3d01SJens Wiklander 
399062e3d01SJens Wiklander 	MPI_CHECK(func(&mpi_t, pop1, pop2));
400062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mod_mpi(&mpi_dest, &mpi_t, &mpi_n));
401062e3d01SJens Wiklander 
402062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
403062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
404062e3d01SJens Wiklander 		put_mpi(&mpi_op1);
405062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
406062e3d01SJens Wiklander 		put_mpi(&mpi_op2);
407062e3d01SJens Wiklander 	put_mpi(&mpi_t);
408062e3d01SJens Wiklander }
409062e3d01SJens Wiklander 
410062e3d01SJens Wiklander void TEE_BigIntAdd(TEE_BigInt *dest, const TEE_BigInt *op1,
411062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
412062e3d01SJens Wiklander {
413062e3d01SJens Wiklander 	bigint_binary(dest, op1, op2, mbedtls_mpi_add_mpi);
414062e3d01SJens Wiklander }
415062e3d01SJens Wiklander 
416062e3d01SJens Wiklander void TEE_BigIntSub(TEE_BigInt *dest, const TEE_BigInt *op1,
417062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
418062e3d01SJens Wiklander {
419062e3d01SJens Wiklander 	bigint_binary(dest, op1, op2, mbedtls_mpi_sub_mpi);
420062e3d01SJens Wiklander }
421062e3d01SJens Wiklander 
422062e3d01SJens Wiklander void TEE_BigIntNeg(TEE_BigInt *dest, const TEE_BigInt *src)
423062e3d01SJens Wiklander {
424062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
425062e3d01SJens Wiklander 
426062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
427062e3d01SJens Wiklander 
428062e3d01SJens Wiklander 	if (dest != src) {
429062e3d01SJens Wiklander 		mbedtls_mpi mpi_src;
430062e3d01SJens Wiklander 
431062e3d01SJens Wiklander 		get_const_mpi(&mpi_src, src);
432062e3d01SJens Wiklander 
433062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_src));
434062e3d01SJens Wiklander 
435062e3d01SJens Wiklander 		put_mpi(&mpi_src);
436062e3d01SJens Wiklander 	}
437062e3d01SJens Wiklander 
438062e3d01SJens Wiklander 	mpi_dest.s *= -1;
439062e3d01SJens Wiklander 
440062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
441062e3d01SJens Wiklander }
442062e3d01SJens Wiklander 
443062e3d01SJens Wiklander void TEE_BigIntMul(TEE_BigInt *dest, const TEE_BigInt *op1,
444062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
445062e3d01SJens Wiklander {
446*98efc118SJerome Forissier 	size_t bs1 = TEE_BigIntGetBitCount(op1);
447*98efc118SJerome Forissier 	size_t bs2 = TEE_BigIntGetBitCount(op2);
448*98efc118SJerome Forissier 	size_t s = TEE_BigIntSizeInU32(bs1) + TEE_BigIntSizeInU32(bs2);
449*98efc118SJerome Forissier 	TEE_BigInt zero[TEE_BigIntSizeInU32(1)] = { 0 };
450*98efc118SJerome Forissier 	TEE_BigInt *tmp = NULL;
451*98efc118SJerome Forissier 
452*98efc118SJerome Forissier 	tmp = mempool_alloc(mbedtls_mpi_mempool, sizeof(uint32_t) * s);
453*98efc118SJerome Forissier 	if (!tmp)
454*98efc118SJerome Forissier 		TEE_Panic(TEE_ERROR_OUT_OF_MEMORY);
455*98efc118SJerome Forissier 
456*98efc118SJerome Forissier 	TEE_BigIntInit(tmp, s);
457*98efc118SJerome Forissier 	TEE_BigIntInit(zero, TEE_BigIntSizeInU32(1));
458*98efc118SJerome Forissier 
459*98efc118SJerome Forissier 	bigint_binary(tmp, op1, op2, mbedtls_mpi_mul_mpi);
460*98efc118SJerome Forissier 
461*98efc118SJerome Forissier 	TEE_BigIntAdd(dest, tmp, zero);
462*98efc118SJerome Forissier 
463*98efc118SJerome Forissier 	mempool_free(mbedtls_mpi_mempool, tmp);
464062e3d01SJens Wiklander }
465062e3d01SJens Wiklander 
466062e3d01SJens Wiklander void TEE_BigIntSquare(TEE_BigInt *dest, const TEE_BigInt *op)
467062e3d01SJens Wiklander {
468062e3d01SJens Wiklander 	TEE_BigIntMul(dest, op, op);
469062e3d01SJens Wiklander }
470062e3d01SJens Wiklander 
471062e3d01SJens Wiklander void TEE_BigIntDiv(TEE_BigInt *dest_q, TEE_BigInt *dest_r,
472062e3d01SJens Wiklander 		   const TEE_BigInt *op1, const TEE_BigInt *op2)
473062e3d01SJens Wiklander {
474062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest_q;
475062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest_r;
476062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
477062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
478062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
479062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
480062e3d01SJens Wiklander 
481062e3d01SJens Wiklander 	get_mpi(&mpi_dest_q, dest_q);
482062e3d01SJens Wiklander 	get_mpi(&mpi_dest_r, dest_r);
483062e3d01SJens Wiklander 
484062e3d01SJens Wiklander 	if (op1 == dest_q)
485062e3d01SJens Wiklander 		pop1 = &mpi_dest_q;
486062e3d01SJens Wiklander 	else if (op1 == dest_r)
487062e3d01SJens Wiklander 		pop1 = &mpi_dest_r;
488062e3d01SJens Wiklander 	else
489062e3d01SJens Wiklander 		get_const_mpi(&mpi_op1, op1);
490062e3d01SJens Wiklander 
491062e3d01SJens Wiklander 	if (op2 == dest_q)
492062e3d01SJens Wiklander 		pop2 = &mpi_dest_q;
493062e3d01SJens Wiklander 	else if (op2 == dest_r)
494062e3d01SJens Wiklander 		pop2 = &mpi_dest_r;
495062e3d01SJens Wiklander 	else if (op2 == op1)
496062e3d01SJens Wiklander 		pop2 = pop1;
497062e3d01SJens Wiklander 	else
498062e3d01SJens Wiklander 		get_const_mpi(&mpi_op2, op2);
499062e3d01SJens Wiklander 
500062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_div_mpi(&mpi_dest_q, &mpi_dest_r, pop1, pop2));
501062e3d01SJens Wiklander 
502062e3d01SJens Wiklander 	put_mpi(&mpi_dest_q);
503062e3d01SJens Wiklander 	put_mpi(&mpi_dest_r);
504062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
505062e3d01SJens Wiklander 		put_mpi(&mpi_op1);
506062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
507062e3d01SJens Wiklander 		put_mpi(&mpi_op2);
508062e3d01SJens Wiklander }
509062e3d01SJens Wiklander 
510062e3d01SJens Wiklander void TEE_BigIntMod(TEE_BigInt *dest, const TEE_BigInt *op, const TEE_BigInt *n)
511062e3d01SJens Wiklander {
512062e3d01SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0)
513062e3d01SJens Wiklander 		API_PANIC("Modulus is too short");
514062e3d01SJens Wiklander 
515062e3d01SJens Wiklander 	bigint_binary(dest, op, n, mbedtls_mpi_mod_mpi);
516062e3d01SJens Wiklander }
517062e3d01SJens Wiklander 
518062e3d01SJens Wiklander void TEE_BigIntAddMod(TEE_BigInt *dest, const TEE_BigInt *op1,
519062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
520062e3d01SJens Wiklander {
521062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_add_mpi);
522062e3d01SJens Wiklander }
523062e3d01SJens Wiklander 
524062e3d01SJens Wiklander void TEE_BigIntSubMod(TEE_BigInt *dest, const TEE_BigInt *op1,
525062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
526062e3d01SJens Wiklander {
527062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_sub_mpi);
528062e3d01SJens Wiklander }
529062e3d01SJens Wiklander 
530062e3d01SJens Wiklander void TEE_BigIntMulMod(TEE_BigInt *dest, const TEE_BigInt *op1,
531062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
532062e3d01SJens Wiklander {
533062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_mul_mpi);
534062e3d01SJens Wiklander }
535062e3d01SJens Wiklander 
536062e3d01SJens Wiklander void TEE_BigIntSquareMod(TEE_BigInt *dest, const TEE_BigInt *op,
537062e3d01SJens Wiklander 			 const TEE_BigInt *n)
538062e3d01SJens Wiklander {
539062e3d01SJens Wiklander 	TEE_BigIntMulMod(dest, op, op, n);
540062e3d01SJens Wiklander }
541062e3d01SJens Wiklander 
542062e3d01SJens Wiklander void TEE_BigIntInvMod(TEE_BigInt *dest, const TEE_BigInt *op,
543062e3d01SJens Wiklander 		      const TEE_BigInt *n)
544062e3d01SJens Wiklander {
545062e3d01SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0 || TEE_BigIntCmpS32(op, 0) == 0)
546062e3d01SJens Wiklander 		API_PANIC("too small modulus or trying to invert zero");
547062e3d01SJens Wiklander 
548062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
549062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
550062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
551062e3d01SJens Wiklander 	mbedtls_mpi *pop = &mpi_op;
552062e3d01SJens Wiklander 
553062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
554062e3d01SJens Wiklander 	get_const_mpi(&mpi_n, n);
555062e3d01SJens Wiklander 
556062e3d01SJens Wiklander 	if (op == dest)
557062e3d01SJens Wiklander 		pop = &mpi_dest;
558062e3d01SJens Wiklander 	else
559062e3d01SJens Wiklander 		get_const_mpi(&mpi_op, op);
560062e3d01SJens Wiklander 
561062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_inv_mod(&mpi_dest, pop, &mpi_n));
562062e3d01SJens Wiklander 
563062e3d01SJens Wiklander 	put_mpi(&mpi_dest);
564062e3d01SJens Wiklander 	put_mpi(&mpi_n);
565062e3d01SJens Wiklander 	if (pop == &mpi_op)
566062e3d01SJens Wiklander 		put_mpi(&mpi_op);
567062e3d01SJens Wiklander }
568062e3d01SJens Wiklander 
569062e3d01SJens Wiklander bool TEE_BigIntRelativePrime(const TEE_BigInt *op1, const TEE_BigInt *op2)
570062e3d01SJens Wiklander {
571062e3d01SJens Wiklander 	bool rc;
572062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
573062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
574062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
575062e3d01SJens Wiklander 	mbedtls_mpi gcd;
576062e3d01SJens Wiklander 
577062e3d01SJens Wiklander 	get_const_mpi(&mpi_op1, op1);
578062e3d01SJens Wiklander 
579062e3d01SJens Wiklander 	if (op2 == op1)
580062e3d01SJens Wiklander 		pop2 = &mpi_op1;
581062e3d01SJens Wiklander 	else
582062e3d01SJens Wiklander 		get_const_mpi(&mpi_op2, op2);
583062e3d01SJens Wiklander 
584062e3d01SJens Wiklander 	get_mpi(&gcd, NULL);
585062e3d01SJens Wiklander 
586062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_gcd(&gcd, &mpi_op1, &mpi_op2));
587062e3d01SJens Wiklander 
588062e3d01SJens Wiklander 	rc = !mbedtls_mpi_cmp_int(&gcd, 1);
589062e3d01SJens Wiklander 
590062e3d01SJens Wiklander 	put_mpi(&gcd);
591062e3d01SJens Wiklander 	put_mpi(&mpi_op1);
592062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
593062e3d01SJens Wiklander 		put_mpi(&mpi_op2);
594062e3d01SJens Wiklander 
595062e3d01SJens Wiklander 	return rc;
596062e3d01SJens Wiklander }
597062e3d01SJens Wiklander 
598062e3d01SJens Wiklander static bool mpi_is_odd(mbedtls_mpi *x)
599062e3d01SJens Wiklander {
600062e3d01SJens Wiklander 	return mbedtls_mpi_get_bit(x, 0);
601062e3d01SJens Wiklander }
602062e3d01SJens Wiklander 
603062e3d01SJens Wiklander static bool mpi_is_even(mbedtls_mpi *x)
604062e3d01SJens Wiklander {
605062e3d01SJens Wiklander 	return !mpi_is_odd(x);
606062e3d01SJens Wiklander }
607062e3d01SJens Wiklander 
608062e3d01SJens Wiklander /*
609062e3d01SJens Wiklander  * Based on libmpa implementation __mpa_egcd(), modified to work with MPI
610062e3d01SJens Wiklander  * instead.
611062e3d01SJens Wiklander  */
612062e3d01SJens Wiklander static void mpi_egcd(mbedtls_mpi *gcd, mbedtls_mpi *a, mbedtls_mpi *b,
613062e3d01SJens Wiklander 		     mbedtls_mpi *x_in, mbedtls_mpi *y_in)
614062e3d01SJens Wiklander {
615062e3d01SJens Wiklander 	mbedtls_mpi_uint k;
616062e3d01SJens Wiklander 	mbedtls_mpi A;
617062e3d01SJens Wiklander 	mbedtls_mpi B;
618062e3d01SJens Wiklander 	mbedtls_mpi C;
619062e3d01SJens Wiklander 	mbedtls_mpi D;
620062e3d01SJens Wiklander 	mbedtls_mpi x;
621062e3d01SJens Wiklander 	mbedtls_mpi y;
622062e3d01SJens Wiklander 	mbedtls_mpi u;
623062e3d01SJens Wiklander 
624062e3d01SJens Wiklander 	get_mpi(&A, NULL);
625062e3d01SJens Wiklander 	get_mpi(&B, NULL);
626062e3d01SJens Wiklander 	get_mpi(&C, NULL);
627062e3d01SJens Wiklander 	get_mpi(&D, NULL);
628062e3d01SJens Wiklander 	get_mpi(&x, NULL);
629062e3d01SJens Wiklander 	get_mpi(&y, NULL);
630062e3d01SJens Wiklander 	get_mpi(&u, NULL);
631062e3d01SJens Wiklander 
632062e3d01SJens Wiklander 	/* have y < x from assumption */
633062e3d01SJens Wiklander 	if (!mbedtls_mpi_cmp_int(y_in, 0)) {
634062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_lset(a, 1));
635062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_lset(b, 0));
636062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(gcd, x_in));
637062e3d01SJens Wiklander 		goto out;
638062e3d01SJens Wiklander 	}
639062e3d01SJens Wiklander 
640062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&x, x_in));
641062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&y, y_in));
642062e3d01SJens Wiklander 
643062e3d01SJens Wiklander 	k = 0;
644062e3d01SJens Wiklander 	while (mpi_is_even(&x) && mpi_is_even(&y)) {
645062e3d01SJens Wiklander 		k++;
646062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&x, 1));
647062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&y, 1));
648062e3d01SJens Wiklander 	}
649062e3d01SJens Wiklander 
650062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&u, &x));
651062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(gcd, &y));
652062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&A, 1));
653062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&B, 0));
654062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&C, 0));
655062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&D, 1));
656062e3d01SJens Wiklander 
657062e3d01SJens Wiklander 	while (mbedtls_mpi_cmp_int(&u, 0)) {
658062e3d01SJens Wiklander 		while (mpi_is_even(&u)) {
659062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&u, 1));
660062e3d01SJens Wiklander 			if (mpi_is_odd(&A) || mpi_is_odd(&B)) {
661062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_add_mpi(&A, &A, &y));
662062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &x));
663062e3d01SJens Wiklander 			}
664062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&A, 1));
665062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&B, 1));
666062e3d01SJens Wiklander 		}
667062e3d01SJens Wiklander 
668062e3d01SJens Wiklander 		while (mpi_is_even(gcd)) {
669062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(gcd, 1));
670062e3d01SJens Wiklander 			if (mpi_is_odd(&C) || mpi_is_odd(&D)) {
671062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_add_mpi(&C, &C, &y));
672062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &x));
673062e3d01SJens Wiklander 			}
674062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&C, 1));
675062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&D, 1));
676062e3d01SJens Wiklander 
677062e3d01SJens Wiklander 		}
678062e3d01SJens Wiklander 
679062e3d01SJens Wiklander 		if (mbedtls_mpi_cmp_mpi(&u, gcd) >= 0) {
680062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&u, &u, gcd));
681062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&A, &A, &C));
682062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &D));
683062e3d01SJens Wiklander 		} else {
684062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(gcd, gcd, &u));
685062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&C, &C, &A));
686062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &B));
687062e3d01SJens Wiklander 		}
688062e3d01SJens Wiklander 	}
689062e3d01SJens Wiklander 
690062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(a, &C));
691062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(b, &D));
692062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_shift_l(gcd, k));
693062e3d01SJens Wiklander 
694062e3d01SJens Wiklander out:
695062e3d01SJens Wiklander 	put_mpi(&A);
696062e3d01SJens Wiklander 	put_mpi(&B);
697062e3d01SJens Wiklander 	put_mpi(&C);
698062e3d01SJens Wiklander 	put_mpi(&D);
699062e3d01SJens Wiklander 	put_mpi(&x);
700062e3d01SJens Wiklander 	put_mpi(&y);
701062e3d01SJens Wiklander 	put_mpi(&u);
702062e3d01SJens Wiklander }
703062e3d01SJens Wiklander 
704062e3d01SJens Wiklander void TEE_BigIntComputeExtendedGcd(TEE_BigInt *gcd, TEE_BigInt *u,
705062e3d01SJens Wiklander 				  TEE_BigInt *v, const TEE_BigInt *op1,
706062e3d01SJens Wiklander 				  const TEE_BigInt *op2)
707062e3d01SJens Wiklander {
708062e3d01SJens Wiklander 	mbedtls_mpi mpi_gcd_res;
709062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
710062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
711062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
712062e3d01SJens Wiklander 
713062e3d01SJens Wiklander 	get_mpi(&mpi_gcd_res, gcd);
714062e3d01SJens Wiklander 	get_const_mpi(&mpi_op1, op1);
715062e3d01SJens Wiklander 
716062e3d01SJens Wiklander 	if (op2 == op1)
717062e3d01SJens Wiklander 		pop2 = &mpi_op1;
718062e3d01SJens Wiklander 	else
719062e3d01SJens Wiklander 		get_const_mpi(&mpi_op2, op2);
720062e3d01SJens Wiklander 
721062e3d01SJens Wiklander 	if (!u && !v) {
722062e3d01SJens Wiklander 		if (gcd)
723062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_gcd(&mpi_gcd_res, &mpi_op1,
724062e3d01SJens Wiklander 						  pop2));
725062e3d01SJens Wiklander 	} else {
726062e3d01SJens Wiklander 		mbedtls_mpi mpi_u;
727062e3d01SJens Wiklander 		mbedtls_mpi mpi_v;
728062e3d01SJens Wiklander 		int8_t s1 = mpi_op1.s;
729062e3d01SJens Wiklander 		int8_t s2 = pop2->s;
730062e3d01SJens Wiklander 		int cmp;
731062e3d01SJens Wiklander 
732062e3d01SJens Wiklander 		mpi_op1.s = 1;
733062e3d01SJens Wiklander 		pop2->s = 1;
734062e3d01SJens Wiklander 
735062e3d01SJens Wiklander 		get_mpi(&mpi_u, u);
736062e3d01SJens Wiklander 		get_mpi(&mpi_v, v);
737062e3d01SJens Wiklander 
738062e3d01SJens Wiklander 		cmp = mbedtls_mpi_cmp_abs(&mpi_op1, pop2);
739062e3d01SJens Wiklander 		if (cmp == 0) {
740062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_copy(&mpi_gcd_res, &mpi_op1));
741062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_lset(&mpi_u, 1));
742062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_lset(&mpi_v, 0));
743062e3d01SJens Wiklander 		} else if (cmp > 0) {
744062e3d01SJens Wiklander 			mpi_egcd(&mpi_gcd_res, &mpi_u, &mpi_v, &mpi_op1, pop2);
745062e3d01SJens Wiklander 		} else {
746062e3d01SJens Wiklander 			mpi_egcd(&mpi_gcd_res, &mpi_v, &mpi_u, pop2, &mpi_op1);
747062e3d01SJens Wiklander 		}
748062e3d01SJens Wiklander 
749062e3d01SJens Wiklander 		mpi_u.s *= s1;
750062e3d01SJens Wiklander 		mpi_v.s *= s2;
751062e3d01SJens Wiklander 
752062e3d01SJens Wiklander 		put_mpi(&mpi_u);
753062e3d01SJens Wiklander 		put_mpi(&mpi_v);
754062e3d01SJens Wiklander 	}
755062e3d01SJens Wiklander 
756062e3d01SJens Wiklander 	put_mpi(&mpi_gcd_res);
757062e3d01SJens Wiklander 	put_mpi(&mpi_op1);
758062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
759062e3d01SJens Wiklander 		put_mpi(&mpi_op2);
760062e3d01SJens Wiklander }
761062e3d01SJens Wiklander 
762062e3d01SJens Wiklander static int rng_read(void *ignored __unused, unsigned char *buf, size_t blen)
763062e3d01SJens Wiklander {
764062e3d01SJens Wiklander 	if (utee_cryp_random_number_generate(buf, blen))
765062e3d01SJens Wiklander 		return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
766062e3d01SJens Wiklander 	return 0;
767062e3d01SJens Wiklander }
768062e3d01SJens Wiklander 
769062e3d01SJens Wiklander int32_t TEE_BigIntIsProbablePrime(const TEE_BigInt *op,
770062e3d01SJens Wiklander 				  uint32_t confidenceLevel __unused)
771062e3d01SJens Wiklander {
772062e3d01SJens Wiklander 	int rc;
773062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
774062e3d01SJens Wiklander 
775062e3d01SJens Wiklander 	get_const_mpi(&mpi_op, op);
776062e3d01SJens Wiklander 
777062e3d01SJens Wiklander 	rc = mbedtls_mpi_is_prime(&mpi_op, rng_read, NULL);
778062e3d01SJens Wiklander 
779062e3d01SJens Wiklander 	put_mpi(&mpi_op);
780062e3d01SJens Wiklander 
781062e3d01SJens Wiklander 	if (rc)
782062e3d01SJens Wiklander 		return 0;
783062e3d01SJens Wiklander 
784062e3d01SJens Wiklander 	return 1;
785062e3d01SJens Wiklander }
786062e3d01SJens Wiklander 
787062e3d01SJens Wiklander /*
788062e3d01SJens Wiklander  * Not so fast FMM implementation based on the normal big int functions.
789062e3d01SJens Wiklander  *
790062e3d01SJens Wiklander  * Note that these functions (along with all the other functions in this
791062e3d01SJens Wiklander  * file) only are used directly by the TA doing bigint arithmetics on its
792062e3d01SJens Wiklander  * own. Performance of RSA operations in TEE Internal API are not affected
793062e3d01SJens Wiklander  * by this.
794062e3d01SJens Wiklander  */
795062e3d01SJens Wiklander void TEE_BigIntInitFMM(TEE_BigIntFMM *bigIntFMM, uint32_t len)
796062e3d01SJens Wiklander {
797062e3d01SJens Wiklander 	TEE_BigIntInit(bigIntFMM, len);
798062e3d01SJens Wiklander }
799062e3d01SJens Wiklander 
800062e3d01SJens Wiklander void TEE_BigIntInitFMMContext(TEE_BigIntFMMContext *context __unused,
801062e3d01SJens Wiklander 			      uint32_t len __unused,
802062e3d01SJens Wiklander 			      const TEE_BigInt *modulus __unused)
803062e3d01SJens Wiklander {
804062e3d01SJens Wiklander }
805062e3d01SJens Wiklander 
806062e3d01SJens Wiklander uint32_t TEE_BigIntFMMSizeInU32(uint32_t modulusSizeInBits)
807062e3d01SJens Wiklander {
808062e3d01SJens Wiklander 	return TEE_BigIntSizeInU32(modulusSizeInBits);
809062e3d01SJens Wiklander }
810062e3d01SJens Wiklander 
811062e3d01SJens Wiklander uint32_t TEE_BigIntFMMContextSizeInU32(uint32_t modulusSizeInBits __unused)
812062e3d01SJens Wiklander {
813062e3d01SJens Wiklander 	/* Return something larger than 0 to keep malloc() and friends happy */
814062e3d01SJens Wiklander 	return 1;
815062e3d01SJens Wiklander }
816062e3d01SJens Wiklander 
817062e3d01SJens Wiklander void TEE_BigIntConvertToFMM(TEE_BigIntFMM *dest, const TEE_BigInt *src,
818062e3d01SJens Wiklander 			    const TEE_BigInt *n,
819062e3d01SJens Wiklander 			    const TEE_BigIntFMMContext *context __unused)
820062e3d01SJens Wiklander {
821062e3d01SJens Wiklander 	TEE_BigIntMod(dest, src, n);
822062e3d01SJens Wiklander }
823062e3d01SJens Wiklander 
824062e3d01SJens Wiklander void TEE_BigIntConvertFromFMM(TEE_BigInt *dest, const TEE_BigIntFMM *src,
825062e3d01SJens Wiklander 			      const TEE_BigInt *n __unused,
826062e3d01SJens Wiklander 			      const TEE_BigIntFMMContext *context __unused)
827062e3d01SJens Wiklander {
828062e3d01SJens Wiklander 	mbedtls_mpi mpi_dst;
829062e3d01SJens Wiklander 	mbedtls_mpi mpi_src;
830062e3d01SJens Wiklander 
831062e3d01SJens Wiklander 	get_mpi(&mpi_dst, dest);
832062e3d01SJens Wiklander 	get_const_mpi(&mpi_src, src);
833062e3d01SJens Wiklander 
834062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&mpi_dst, &mpi_src));
835062e3d01SJens Wiklander 
836062e3d01SJens Wiklander 	put_mpi(&mpi_dst);
837062e3d01SJens Wiklander 	put_mpi(&mpi_src);
838062e3d01SJens Wiklander }
839062e3d01SJens Wiklander 
840062e3d01SJens Wiklander void TEE_BigIntComputeFMM(TEE_BigIntFMM *dest, const TEE_BigIntFMM *op1,
841062e3d01SJens Wiklander 			  const TEE_BigIntFMM *op2, const TEE_BigInt *n,
842062e3d01SJens Wiklander 			  const TEE_BigIntFMMContext *context __unused)
843062e3d01SJens Wiklander {
844062e3d01SJens Wiklander 	mbedtls_mpi mpi_dst;
845062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
846062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
847062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
848062e3d01SJens Wiklander 	mbedtls_mpi mpi_t;
849062e3d01SJens Wiklander 
850062e3d01SJens Wiklander 	get_mpi(&mpi_dst, dest);
851062e3d01SJens Wiklander 	get_const_mpi(&mpi_op1, op1);
852062e3d01SJens Wiklander 	get_const_mpi(&mpi_op2, op2);
853062e3d01SJens Wiklander 	get_const_mpi(&mpi_n, n);
854062e3d01SJens Wiklander 	get_mpi(&mpi_t, NULL);
855062e3d01SJens Wiklander 
856062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mul_mpi(&mpi_t, &mpi_op1, &mpi_op2));
857062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mod_mpi(&mpi_dst, &mpi_t, &mpi_n));
858062e3d01SJens Wiklander 
859062e3d01SJens Wiklander 	put_mpi(&mpi_t);
860062e3d01SJens Wiklander 	put_mpi(&mpi_n);
861062e3d01SJens Wiklander 	put_mpi(&mpi_op2);
862062e3d01SJens Wiklander 	put_mpi(&mpi_op1);
863062e3d01SJens Wiklander 	put_mpi(&mpi_dst);
864062e3d01SJens Wiklander }
865