xref: /optee_os/lib/libutee/tee_api_arith_mpi.c (revision 420232951deba3e79232a90b8f0fa03da68fc3db)
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 
16628e1eb0SJens Wiklander #define MPI_MEMPOOL_SIZE	(12 * 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 {
45b2dd8747SJens Wiklander 	static uint8_t data[MPI_MEMPOOL_SIZE] __aligned(MEMPOOL_ALIGN);
46062e3d01SJens Wiklander 
47062e3d01SJens Wiklander 	mbedtls_mpi_mempool = mempool_alloc_pool(data, sizeof(data), NULL);
48062e3d01SJens Wiklander 	if (!mbedtls_mpi_mempool)
49062e3d01SJens Wiklander 		API_PANIC("Failed to initialize memory pool");
50062e3d01SJens Wiklander }
51062e3d01SJens Wiklander 
52062e3d01SJens Wiklander struct bigint_hdr {
53062e3d01SJens Wiklander 	int32_t sign;
54062e3d01SJens Wiklander 	uint16_t alloc_size;
55062e3d01SJens Wiklander 	uint16_t nblimbs;
56062e3d01SJens Wiklander };
57062e3d01SJens Wiklander 
58062e3d01SJens Wiklander #define BIGINT_HDR_SIZE_IN_U32	2
59062e3d01SJens Wiklander 
607696ab7fSJens Wiklander static TEE_Result copy_mpi_to_bigint(mbedtls_mpi *mpi, TEE_BigInt *bigInt)
61062e3d01SJens Wiklander {
62062e3d01SJens Wiklander 	struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt;
637696ab7fSJens Wiklander 	size_t n = mpi->n;
64062e3d01SJens Wiklander 
657696ab7fSJens Wiklander 	/* Trim of eventual insignificant zeroes */
667696ab7fSJens Wiklander 	while (n && !mpi->p[n - 1])
677696ab7fSJens Wiklander 		n--;
687696ab7fSJens Wiklander 
697696ab7fSJens Wiklander 	if (hdr->alloc_size < n)
707696ab7fSJens Wiklander 		return TEE_ERROR_OVERFLOW;
717696ab7fSJens Wiklander 
727696ab7fSJens Wiklander 	hdr->nblimbs = n;
737696ab7fSJens Wiklander 	hdr->sign = mpi->s;
747696ab7fSJens Wiklander 	memcpy(hdr + 1, mpi->p, mpi->n * sizeof(mbedtls_mpi_uint));
757696ab7fSJens Wiklander 
767696ab7fSJens Wiklander 	return TEE_SUCCESS;
77062e3d01SJens Wiklander }
78062e3d01SJens Wiklander 
79062e3d01SJens Wiklander /*
80062e3d01SJens Wiklander  * Initializes a MPI.
81062e3d01SJens Wiklander  *
827696ab7fSJens Wiklander  * A temporary MPI is allocated and if a bigInt is supplied the MPI is
837696ab7fSJens Wiklander  * initialized with the value of the bigInt.
84062e3d01SJens Wiklander  */
857696ab7fSJens Wiklander static void get_mpi(mbedtls_mpi *mpi, const TEE_BigInt *bigInt)
86062e3d01SJens Wiklander {
87062e3d01SJens Wiklander 	/*
88062e3d01SJens Wiklander 	 * The way the GP spec is defining the bignums it's
89062e3d01SJens Wiklander 	 * difficult/tricky to do it using 64-bit arithmetics given that
90062e3d01SJens Wiklander 	 * we'd need 64-bit alignment of the data as well.
91062e3d01SJens Wiklander 	 */
92062e3d01SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(mbedtls_mpi_uint) == sizeof(uint32_t));
93062e3d01SJens Wiklander 
94062e3d01SJens Wiklander 	/*
95062e3d01SJens Wiklander 	 * The struct bigint_hdr is the overhead added to the bigint and
96062e3d01SJens Wiklander 	 * is required to take exactly 2 uint32_t.
97062e3d01SJens Wiklander 	 */
98062e3d01SJens Wiklander 	COMPILE_TIME_ASSERT(sizeof(struct bigint_hdr) ==
99062e3d01SJens Wiklander 			    sizeof(uint32_t) * BIGINT_HDR_SIZE_IN_U32);
100062e3d01SJens Wiklander 
101062e3d01SJens Wiklander 	mbedtls_mpi_init_mempool(mpi);
102062e3d01SJens Wiklander 
1037696ab7fSJens Wiklander 	if (bigInt) {
1047696ab7fSJens Wiklander 		const struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt;
1057696ab7fSJens Wiklander 		const mbedtls_mpi_uint *p = (const mbedtls_mpi_uint *)(hdr + 1);
1067696ab7fSJens Wiklander 		size_t n = hdr->nblimbs;
107062e3d01SJens Wiklander 
1087696ab7fSJens Wiklander 		/* Trim of eventual insignificant zeroes */
1097696ab7fSJens Wiklander 		while (n && !p[n - 1])
1107696ab7fSJens Wiklander 			n--;
111062e3d01SJens Wiklander 
1127696ab7fSJens Wiklander 		MPI_CHECK(mbedtls_mpi_grow(mpi, n));
1137696ab7fSJens Wiklander 		mpi->s = hdr->sign;
1147696ab7fSJens Wiklander 		memcpy(mpi->p, p, n * sizeof(mbedtls_mpi_uint));
115062e3d01SJens Wiklander 	}
116062e3d01SJens Wiklander }
117062e3d01SJens Wiklander 
118fe03ed8bSJens Wiklander void TEE_BigIntInit(TEE_BigInt *bigInt, size_t len)
119062e3d01SJens Wiklander {
120062e3d01SJens Wiklander 	struct bigint_hdr *hdr = (struct bigint_hdr *)bigInt;
121062e3d01SJens Wiklander 
122fe03ed8bSJens Wiklander 	static_assert(MBEDTLS_MPI_MAX_LIMBS + BIGINT_HDR_SIZE_IN_U32 >=
123fe03ed8bSJens Wiklander 		      CFG_TA_BIGNUM_MAX_BITS / 32);
124fe03ed8bSJens Wiklander 
125e6e7781fSJens Wiklander 	memset(bigInt, 0, len * sizeof(uint32_t));
126062e3d01SJens Wiklander 	hdr->sign = 1;
127fe03ed8bSJens Wiklander 
128fe03ed8bSJens Wiklander 	/* "gpd.tee.arith.maxBigIntSize" is assigned CFG_TA_BIGNUM_MAX_BITS */
129fe03ed8bSJens Wiklander 	if (len > CFG_TA_BIGNUM_MAX_BITS / 4)
130062e3d01SJens Wiklander 		API_PANIC("Too large bigint");
131062e3d01SJens Wiklander 	hdr->alloc_size = len - BIGINT_HDR_SIZE_IN_U32;
132062e3d01SJens Wiklander }
133062e3d01SJens Wiklander 
134fe03ed8bSJens Wiklander void __GP11_TEE_BigIntInit(TEE_BigInt *bigInt, uint32_t len)
135fe03ed8bSJens Wiklander {
136fe03ed8bSJens Wiklander 	TEE_BigIntInit(bigInt, len);
137fe03ed8bSJens Wiklander }
138fe03ed8bSJens Wiklander 
139062e3d01SJens Wiklander TEE_Result TEE_BigIntConvertFromOctetString(TEE_BigInt *dest,
140062e3d01SJens Wiklander 					    const uint8_t *buffer,
141fe03ed8bSJens Wiklander 					    size_t bufferLen, int32_t sign)
142062e3d01SJens Wiklander {
143062e3d01SJens Wiklander 	TEE_Result res;
144062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
145062e3d01SJens Wiklander 
1467696ab7fSJens Wiklander 	get_mpi(&mpi_dest, NULL);
147062e3d01SJens Wiklander 
148062e3d01SJens Wiklander 	if (mbedtls_mpi_read_binary(&mpi_dest,  buffer, bufferLen))
149062e3d01SJens Wiklander 		res = TEE_ERROR_OVERFLOW;
150062e3d01SJens Wiklander 	else
151062e3d01SJens Wiklander 		res = TEE_SUCCESS;
152062e3d01SJens Wiklander 
153062e3d01SJens Wiklander 	if (sign < 0)
154062e3d01SJens Wiklander 		mpi_dest.s = -1;
155062e3d01SJens Wiklander 
1567696ab7fSJens Wiklander 	if (!res)
1577696ab7fSJens Wiklander 		res = copy_mpi_to_bigint(&mpi_dest, dest);
1587696ab7fSJens Wiklander 
1597696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
160062e3d01SJens Wiklander 
161062e3d01SJens Wiklander 	return res;
162062e3d01SJens Wiklander }
163062e3d01SJens Wiklander 
164fe03ed8bSJens Wiklander TEE_Result __GP11_TEE_BigIntConvertFromOctetString(TEE_BigInt *dest,
165fe03ed8bSJens Wiklander 						   const uint8_t *buffer,
166fe03ed8bSJens Wiklander 						   uint32_t bufferLen,
167fe03ed8bSJens Wiklander 						   int32_t sign)
168fe03ed8bSJens Wiklander {
169fe03ed8bSJens Wiklander 	return TEE_BigIntConvertFromOctetString(dest, buffer, bufferLen, sign);
170fe03ed8bSJens Wiklander }
171fe03ed8bSJens Wiklander 
172fe03ed8bSJens Wiklander TEE_Result TEE_BigIntConvertToOctetString(uint8_t *buffer, size_t *bufferLen,
173062e3d01SJens Wiklander 					  const TEE_BigInt *bigInt)
174062e3d01SJens Wiklander {
175062e3d01SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
176062e3d01SJens Wiklander 	mbedtls_mpi mpi;
177062e3d01SJens Wiklander 	size_t sz;
178062e3d01SJens Wiklander 
1797696ab7fSJens Wiklander 	get_mpi(&mpi, bigInt);
180062e3d01SJens Wiklander 
181062e3d01SJens Wiklander 	sz = mbedtls_mpi_size(&mpi);
182062e3d01SJens Wiklander 	if (sz <= *bufferLen)
183062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_write_binary(&mpi, buffer, sz));
184062e3d01SJens Wiklander 	else
185062e3d01SJens Wiklander 		res = TEE_ERROR_SHORT_BUFFER;
186062e3d01SJens Wiklander 
187062e3d01SJens Wiklander 	*bufferLen = sz;
188062e3d01SJens Wiklander 
1897696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
190062e3d01SJens Wiklander 
191062e3d01SJens Wiklander 	return res;
192062e3d01SJens Wiklander }
193062e3d01SJens Wiklander 
194fe03ed8bSJens Wiklander TEE_Result __GP11_TEE_BigIntConvertToOctetString(uint8_t *buffer,
195fe03ed8bSJens Wiklander 						 uint32_t *bufferLen,
196fe03ed8bSJens Wiklander 						 const TEE_BigInt *bigInt)
197fe03ed8bSJens Wiklander {
198fe03ed8bSJens Wiklander 	TEE_Result res = TEE_SUCCESS;
199fe03ed8bSJens Wiklander 	size_t l = *bufferLen;
200fe03ed8bSJens Wiklander 
201fe03ed8bSJens Wiklander 	res = TEE_BigIntConvertToOctetString(buffer, &l, bigInt);
202fe03ed8bSJens Wiklander 	*bufferLen = l;
203fe03ed8bSJens Wiklander 	return res;
204fe03ed8bSJens Wiklander }
205fe03ed8bSJens Wiklander 
206062e3d01SJens Wiklander void TEE_BigIntConvertFromS32(TEE_BigInt *dest, int32_t shortVal)
207062e3d01SJens Wiklander {
208062e3d01SJens Wiklander 	mbedtls_mpi mpi;
209062e3d01SJens Wiklander 
210062e3d01SJens Wiklander 	get_mpi(&mpi, dest);
211062e3d01SJens Wiklander 
212062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&mpi, shortVal));
213062e3d01SJens Wiklander 
2147696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi, dest));
2157696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
216062e3d01SJens Wiklander }
217062e3d01SJens Wiklander 
218062e3d01SJens Wiklander TEE_Result TEE_BigIntConvertToS32(int32_t *dest, const TEE_BigInt *src)
219062e3d01SJens Wiklander {
220062e3d01SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
221062e3d01SJens Wiklander 	mbedtls_mpi mpi;
222062e3d01SJens Wiklander 	uint32_t v;
223062e3d01SJens Wiklander 
2247696ab7fSJens Wiklander 	get_mpi(&mpi, src);
225062e3d01SJens Wiklander 
226062e3d01SJens Wiklander 	if (mbedtls_mpi_write_binary(&mpi, (void *)&v, sizeof(v))) {
227062e3d01SJens Wiklander 		res = TEE_ERROR_OVERFLOW;
228062e3d01SJens Wiklander 		goto out;
229062e3d01SJens Wiklander 	}
230062e3d01SJens Wiklander 
231062e3d01SJens Wiklander 	if (mpi.s > 0) {
232062e3d01SJens Wiklander 		if (ADD_OVERFLOW(0, TEE_U32_FROM_BIG_ENDIAN(v), dest))
233062e3d01SJens Wiklander 			res = TEE_ERROR_OVERFLOW;
234062e3d01SJens Wiklander 	} else {
235062e3d01SJens Wiklander 		if (SUB_OVERFLOW(0, TEE_U32_FROM_BIG_ENDIAN(v), dest))
236062e3d01SJens Wiklander 			res = TEE_ERROR_OVERFLOW;
237062e3d01SJens Wiklander 	}
238062e3d01SJens Wiklander 
239062e3d01SJens Wiklander out:
2407696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
241062e3d01SJens Wiklander 
242062e3d01SJens Wiklander 	return res;
243062e3d01SJens Wiklander }
244062e3d01SJens Wiklander 
245062e3d01SJens Wiklander int32_t TEE_BigIntCmp(const TEE_BigInt *op1, const TEE_BigInt *op2)
246062e3d01SJens Wiklander {
247062e3d01SJens Wiklander 	mbedtls_mpi mpi1;
248062e3d01SJens Wiklander 	mbedtls_mpi mpi2;
249062e3d01SJens Wiklander 	int32_t rc;
250062e3d01SJens Wiklander 
2517696ab7fSJens Wiklander 	get_mpi(&mpi1, op1);
2527696ab7fSJens Wiklander 	get_mpi(&mpi2, op2);
253062e3d01SJens Wiklander 
254062e3d01SJens Wiklander 	rc = mbedtls_mpi_cmp_mpi(&mpi1, &mpi2);
255062e3d01SJens Wiklander 
2567696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi1);
2577696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi2);
258062e3d01SJens Wiklander 
259062e3d01SJens Wiklander 	return rc;
260062e3d01SJens Wiklander }
261062e3d01SJens Wiklander 
262062e3d01SJens Wiklander int32_t TEE_BigIntCmpS32(const TEE_BigInt *op, int32_t shortVal)
263062e3d01SJens Wiklander {
264062e3d01SJens Wiklander 	mbedtls_mpi mpi;
265062e3d01SJens Wiklander 	int32_t rc;
266062e3d01SJens Wiklander 
2677696ab7fSJens Wiklander 	get_mpi(&mpi, op);
268062e3d01SJens Wiklander 
269062e3d01SJens Wiklander 	rc = mbedtls_mpi_cmp_int(&mpi, shortVal);
270062e3d01SJens Wiklander 
2717696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
272062e3d01SJens Wiklander 
273062e3d01SJens Wiklander 	return rc;
274062e3d01SJens Wiklander }
275062e3d01SJens Wiklander 
276062e3d01SJens Wiklander void TEE_BigIntShiftRight(TEE_BigInt *dest, const TEE_BigInt *op, size_t bits)
277062e3d01SJens Wiklander {
278062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
279062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
280062e3d01SJens Wiklander 
281062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
282062e3d01SJens Wiklander 
283062e3d01SJens Wiklander 	if (dest == op) {
284062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits));
285062e3d01SJens Wiklander 		goto out;
286062e3d01SJens Wiklander 	}
287062e3d01SJens Wiklander 
2887696ab7fSJens Wiklander 	get_mpi(&mpi_op, op);
289062e3d01SJens Wiklander 
290062e3d01SJens Wiklander 	if (mbedtls_mpi_size(&mpi_dest) >= mbedtls_mpi_size(&mpi_op)) {
291062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_op));
292062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_dest, bits));
293062e3d01SJens Wiklander 	} else {
294062e3d01SJens Wiklander 		mbedtls_mpi mpi_t;
295062e3d01SJens Wiklander 
296062e3d01SJens Wiklander 		get_mpi(&mpi_t, NULL);
297062e3d01SJens Wiklander 
298062e3d01SJens Wiklander 		/*
299062e3d01SJens Wiklander 		 * We're using a temporary buffer to avoid the corner case
300062e3d01SJens Wiklander 		 * where destination is unexpectedly overflowed by up to
301062e3d01SJens Wiklander 		 * @bits number of bits.
302062e3d01SJens Wiklander 		 */
303062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_t, &mpi_op));
304062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&mpi_t, bits));
305062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_t));
306062e3d01SJens Wiklander 
3077696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_t);
308062e3d01SJens Wiklander 	}
309062e3d01SJens Wiklander 
3107696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op);
311062e3d01SJens Wiklander 
312062e3d01SJens Wiklander out:
3137696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest));
3147696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
315062e3d01SJens Wiklander }
316062e3d01SJens Wiklander 
317fe03ed8bSJens Wiklander void __GP11_TEE_BigIntShiftRight(TEE_BigInt *dest, const TEE_BigInt *op,
318fe03ed8bSJens Wiklander 				 uint32_t bits)
319fe03ed8bSJens Wiklander {
320fe03ed8bSJens Wiklander 	TEE_BigIntShiftRight(dest, op, bits);
321fe03ed8bSJens Wiklander }
322fe03ed8bSJens Wiklander 
323062e3d01SJens Wiklander bool TEE_BigIntGetBit(const TEE_BigInt *src, uint32_t bitIndex)
324062e3d01SJens Wiklander {
325062e3d01SJens Wiklander 	bool rc;
326062e3d01SJens Wiklander 	mbedtls_mpi mpi;
327062e3d01SJens Wiklander 
3287696ab7fSJens Wiklander 	get_mpi(&mpi, src);
329062e3d01SJens Wiklander 
330062e3d01SJens Wiklander 	rc = mbedtls_mpi_get_bit(&mpi, bitIndex);
331062e3d01SJens Wiklander 
3327696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
333062e3d01SJens Wiklander 
334062e3d01SJens Wiklander 	return rc;
335062e3d01SJens Wiklander }
336062e3d01SJens Wiklander 
337062e3d01SJens Wiklander uint32_t TEE_BigIntGetBitCount(const TEE_BigInt *src)
338062e3d01SJens Wiklander {
339062e3d01SJens Wiklander 	uint32_t rc;
340062e3d01SJens Wiklander 	mbedtls_mpi mpi;
341062e3d01SJens Wiklander 
3427696ab7fSJens Wiklander 	get_mpi(&mpi, src);
343062e3d01SJens Wiklander 
344062e3d01SJens Wiklander 	rc = mbedtls_mpi_bitlen(&mpi);
345062e3d01SJens Wiklander 
3467696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi);
347062e3d01SJens Wiklander 
348062e3d01SJens Wiklander 	return rc;
349062e3d01SJens Wiklander }
350062e3d01SJens Wiklander 
351*42023295SJens Wiklander TEE_Result TEE_BigIntSetBit(TEE_BigInt *op, uint32_t bitIndex, bool value)
352*42023295SJens Wiklander {
353*42023295SJens Wiklander 	TEE_Result res = TEE_SUCCESS;
354*42023295SJens Wiklander 	mbedtls_mpi mpi = { };
355*42023295SJens Wiklander 	int rc = 0;
356*42023295SJens Wiklander 
357*42023295SJens Wiklander 	get_mpi(&mpi, op);
358*42023295SJens Wiklander 
359*42023295SJens Wiklander 	rc = mbedtls_mpi_set_bit(&mpi, bitIndex, value);
360*42023295SJens Wiklander 	if (rc)
361*42023295SJens Wiklander 		res = TEE_ERROR_OVERFLOW;
362*42023295SJens Wiklander 	else
363*42023295SJens Wiklander 		res = copy_mpi_to_bigint(&mpi, op);
364*42023295SJens Wiklander 
365*42023295SJens Wiklander 	mbedtls_mpi_free(&mpi);
366*42023295SJens Wiklander 
367*42023295SJens Wiklander 	return res;
368*42023295SJens Wiklander }
369*42023295SJens Wiklander 
370af4bcf34SJens Wiklander TEE_Result TEE_BigIntAssign(TEE_BigInt *dest, const TEE_BigInt *src)
371af4bcf34SJens Wiklander {
372af4bcf34SJens Wiklander 	const struct bigint_hdr *src_hdr = (struct bigint_hdr *)src;
373af4bcf34SJens Wiklander 	struct bigint_hdr *dst_hdr = (struct bigint_hdr *)dest;
374af4bcf34SJens Wiklander 
375af4bcf34SJens Wiklander 	if (dst_hdr == src_hdr)
376af4bcf34SJens Wiklander 		return TEE_SUCCESS;
377af4bcf34SJens Wiklander 
378af4bcf34SJens Wiklander 	if (dst_hdr->alloc_size < src_hdr->nblimbs)
379af4bcf34SJens Wiklander 		return TEE_ERROR_OVERFLOW;
380af4bcf34SJens Wiklander 
381af4bcf34SJens Wiklander 	dst_hdr->nblimbs = src_hdr->nblimbs;
382af4bcf34SJens Wiklander 	dst_hdr->sign = src_hdr->sign;
383af4bcf34SJens Wiklander 	memcpy(dst_hdr + 1, src_hdr + 1, src_hdr->nblimbs * sizeof(uint32_t));
384af4bcf34SJens Wiklander 
385af4bcf34SJens Wiklander 	return TEE_SUCCESS;
386af4bcf34SJens Wiklander }
387af4bcf34SJens Wiklander 
388062e3d01SJens Wiklander static void bigint_binary(TEE_BigInt *dest, const TEE_BigInt *op1,
389062e3d01SJens Wiklander 			  const TEE_BigInt *op2,
390062e3d01SJens Wiklander 			  int (*func)(mbedtls_mpi *X, const mbedtls_mpi *A,
391062e3d01SJens Wiklander 				      const mbedtls_mpi *B))
392062e3d01SJens Wiklander {
393062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
394062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
395062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
396062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
397062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
398062e3d01SJens Wiklander 
399062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
400062e3d01SJens Wiklander 
401062e3d01SJens Wiklander 	if (op1 == dest)
402062e3d01SJens Wiklander 		pop1 = &mpi_dest;
403062e3d01SJens Wiklander 	else
4047696ab7fSJens Wiklander 		get_mpi(&mpi_op1, op1);
405062e3d01SJens Wiklander 
406062e3d01SJens Wiklander 	if (op2 == dest)
407062e3d01SJens Wiklander 		pop2 = &mpi_dest;
408062e3d01SJens Wiklander 	else if (op2 == op1)
409062e3d01SJens Wiklander 		pop2 = pop1;
410062e3d01SJens Wiklander 	else
4117696ab7fSJens Wiklander 		get_mpi(&mpi_op2, op2);
412062e3d01SJens Wiklander 
413062e3d01SJens Wiklander 	MPI_CHECK(func(&mpi_dest, pop1, pop2));
414062e3d01SJens Wiklander 
4157696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest));
4167696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
417062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
4187696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op1);
419062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
4207696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op2);
421062e3d01SJens Wiklander }
422062e3d01SJens Wiklander 
423062e3d01SJens Wiklander static void bigint_binary_mod(TEE_BigInt *dest, const TEE_BigInt *op1,
424062e3d01SJens Wiklander 			      const TEE_BigInt *op2, const TEE_BigInt *n,
425062e3d01SJens Wiklander 			      int (*func)(mbedtls_mpi *X, const mbedtls_mpi *A,
426062e3d01SJens Wiklander 					  const mbedtls_mpi *B))
427062e3d01SJens Wiklander {
428062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
429062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
430062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
431062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
432062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
433062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
434062e3d01SJens Wiklander 	mbedtls_mpi mpi_t;
435062e3d01SJens Wiklander 
43666e18280SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0)
43766e18280SJens Wiklander 		API_PANIC("Modulus is too short");
43866e18280SJens Wiklander 
439062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
4407696ab7fSJens Wiklander 	get_mpi(&mpi_n, n);
441062e3d01SJens Wiklander 
442062e3d01SJens Wiklander 	if (op1 == dest)
443062e3d01SJens Wiklander 		pop1 = &mpi_dest;
444062e3d01SJens Wiklander 	else
4457696ab7fSJens Wiklander 		get_mpi(&mpi_op1, op1);
446062e3d01SJens Wiklander 
447062e3d01SJens Wiklander 	if (op2 == dest)
448062e3d01SJens Wiklander 		pop2 = &mpi_dest;
449062e3d01SJens Wiklander 	else if (op2 == op1)
450062e3d01SJens Wiklander 		pop2 = pop1;
451062e3d01SJens Wiklander 	else
4527696ab7fSJens Wiklander 		get_mpi(&mpi_op2, op2);
453062e3d01SJens Wiklander 
454062e3d01SJens Wiklander 	get_mpi(&mpi_t, NULL);
455062e3d01SJens Wiklander 
456062e3d01SJens Wiklander 	MPI_CHECK(func(&mpi_t, pop1, pop2));
457062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mod_mpi(&mpi_dest, &mpi_t, &mpi_n));
458062e3d01SJens Wiklander 
4597696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest));
4607696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
461062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
4627696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op1);
463062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
4647696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op2);
4657696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_t);
46613218059SMatthieu BERTIN 	mbedtls_mpi_free(&mpi_n);
467062e3d01SJens Wiklander }
468062e3d01SJens Wiklander 
469062e3d01SJens Wiklander void TEE_BigIntAdd(TEE_BigInt *dest, const TEE_BigInt *op1,
470062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
471062e3d01SJens Wiklander {
472062e3d01SJens Wiklander 	bigint_binary(dest, op1, op2, mbedtls_mpi_add_mpi);
473062e3d01SJens Wiklander }
474062e3d01SJens Wiklander 
475062e3d01SJens Wiklander void TEE_BigIntSub(TEE_BigInt *dest, const TEE_BigInt *op1,
476062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
477062e3d01SJens Wiklander {
478062e3d01SJens Wiklander 	bigint_binary(dest, op1, op2, mbedtls_mpi_sub_mpi);
479062e3d01SJens Wiklander }
480062e3d01SJens Wiklander 
481062e3d01SJens Wiklander void TEE_BigIntNeg(TEE_BigInt *dest, const TEE_BigInt *src)
482062e3d01SJens Wiklander {
483062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
484062e3d01SJens Wiklander 
485062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
486062e3d01SJens Wiklander 
487062e3d01SJens Wiklander 	if (dest != src) {
488062e3d01SJens Wiklander 		mbedtls_mpi mpi_src;
489062e3d01SJens Wiklander 
4907696ab7fSJens Wiklander 		get_mpi(&mpi_src, src);
491062e3d01SJens Wiklander 
492062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(&mpi_dest, &mpi_src));
493062e3d01SJens Wiklander 
4947696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_src);
495062e3d01SJens Wiklander 	}
496062e3d01SJens Wiklander 
497062e3d01SJens Wiklander 	mpi_dest.s *= -1;
498062e3d01SJens Wiklander 
4997696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest));
5007696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
501062e3d01SJens Wiklander }
502062e3d01SJens Wiklander 
503062e3d01SJens Wiklander void TEE_BigIntMul(TEE_BigInt *dest, const TEE_BigInt *op1,
504062e3d01SJens Wiklander 		   const TEE_BigInt *op2)
505062e3d01SJens Wiklander {
50698efc118SJerome Forissier 	size_t bs1 = TEE_BigIntGetBitCount(op1);
50798efc118SJerome Forissier 	size_t bs2 = TEE_BigIntGetBitCount(op2);
50898efc118SJerome Forissier 	size_t s = TEE_BigIntSizeInU32(bs1) + TEE_BigIntSizeInU32(bs2);
50998efc118SJerome Forissier 	TEE_BigInt zero[TEE_BigIntSizeInU32(1)] = { 0 };
51098efc118SJerome Forissier 	TEE_BigInt *tmp = NULL;
51198efc118SJerome Forissier 
51298efc118SJerome Forissier 	tmp = mempool_alloc(mbedtls_mpi_mempool, sizeof(uint32_t) * s);
51398efc118SJerome Forissier 	if (!tmp)
51498efc118SJerome Forissier 		TEE_Panic(TEE_ERROR_OUT_OF_MEMORY);
51598efc118SJerome Forissier 
51698efc118SJerome Forissier 	TEE_BigIntInit(tmp, s);
51798efc118SJerome Forissier 	TEE_BigIntInit(zero, TEE_BigIntSizeInU32(1));
51898efc118SJerome Forissier 
51998efc118SJerome Forissier 	bigint_binary(tmp, op1, op2, mbedtls_mpi_mul_mpi);
52098efc118SJerome Forissier 
52198efc118SJerome Forissier 	TEE_BigIntAdd(dest, tmp, zero);
52298efc118SJerome Forissier 
52398efc118SJerome Forissier 	mempool_free(mbedtls_mpi_mempool, tmp);
524062e3d01SJens Wiklander }
525062e3d01SJens Wiklander 
526062e3d01SJens Wiklander void TEE_BigIntSquare(TEE_BigInt *dest, const TEE_BigInt *op)
527062e3d01SJens Wiklander {
528062e3d01SJens Wiklander 	TEE_BigIntMul(dest, op, op);
529062e3d01SJens Wiklander }
530062e3d01SJens Wiklander 
531062e3d01SJens Wiklander void TEE_BigIntDiv(TEE_BigInt *dest_q, TEE_BigInt *dest_r,
532062e3d01SJens Wiklander 		   const TEE_BigInt *op1, const TEE_BigInt *op2)
533062e3d01SJens Wiklander {
534062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest_q;
535062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest_r;
536062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
537062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
538062e3d01SJens Wiklander 	mbedtls_mpi *pop1 = &mpi_op1;
539062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
540062e3d01SJens Wiklander 
541062e3d01SJens Wiklander 	get_mpi(&mpi_dest_q, dest_q);
542062e3d01SJens Wiklander 	get_mpi(&mpi_dest_r, dest_r);
543062e3d01SJens Wiklander 
544062e3d01SJens Wiklander 	if (op1 == dest_q)
545062e3d01SJens Wiklander 		pop1 = &mpi_dest_q;
546062e3d01SJens Wiklander 	else if (op1 == dest_r)
547062e3d01SJens Wiklander 		pop1 = &mpi_dest_r;
548062e3d01SJens Wiklander 	else
5497696ab7fSJens Wiklander 		get_mpi(&mpi_op1, op1);
550062e3d01SJens Wiklander 
551062e3d01SJens Wiklander 	if (op2 == dest_q)
552062e3d01SJens Wiklander 		pop2 = &mpi_dest_q;
553062e3d01SJens Wiklander 	else if (op2 == dest_r)
554062e3d01SJens Wiklander 		pop2 = &mpi_dest_r;
555062e3d01SJens Wiklander 	else if (op2 == op1)
556062e3d01SJens Wiklander 		pop2 = pop1;
557062e3d01SJens Wiklander 	else
5587696ab7fSJens Wiklander 		get_mpi(&mpi_op2, op2);
559062e3d01SJens Wiklander 
560062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_div_mpi(&mpi_dest_q, &mpi_dest_r, pop1, pop2));
561062e3d01SJens Wiklander 
562a874dbbdSJens Wiklander 	if (dest_q)
5637696ab7fSJens Wiklander 		MPI_CHECK(copy_mpi_to_bigint(&mpi_dest_q, dest_q));
564a874dbbdSJens Wiklander 	if (dest_r)
5657696ab7fSJens Wiklander 		MPI_CHECK(copy_mpi_to_bigint(&mpi_dest_r, dest_r));
5667696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest_q);
5677696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest_r);
568062e3d01SJens Wiklander 	if (pop1 == &mpi_op1)
5697696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op1);
570062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
5717696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op2);
572062e3d01SJens Wiklander }
573062e3d01SJens Wiklander 
574062e3d01SJens Wiklander void TEE_BigIntMod(TEE_BigInt *dest, const TEE_BigInt *op, const TEE_BigInt *n)
575062e3d01SJens Wiklander {
576062e3d01SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0)
577062e3d01SJens Wiklander 		API_PANIC("Modulus is too short");
578062e3d01SJens Wiklander 
579062e3d01SJens Wiklander 	bigint_binary(dest, op, n, mbedtls_mpi_mod_mpi);
580062e3d01SJens Wiklander }
581062e3d01SJens Wiklander 
582062e3d01SJens Wiklander void TEE_BigIntAddMod(TEE_BigInt *dest, const TEE_BigInt *op1,
583062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
584062e3d01SJens Wiklander {
585062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_add_mpi);
586062e3d01SJens Wiklander }
587062e3d01SJens Wiklander 
588062e3d01SJens Wiklander void TEE_BigIntSubMod(TEE_BigInt *dest, const TEE_BigInt *op1,
589062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
590062e3d01SJens Wiklander {
591062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_sub_mpi);
592062e3d01SJens Wiklander }
593062e3d01SJens Wiklander 
594062e3d01SJens Wiklander void TEE_BigIntMulMod(TEE_BigInt *dest, const TEE_BigInt *op1,
595062e3d01SJens Wiklander 		      const TEE_BigInt *op2, const TEE_BigInt *n)
596062e3d01SJens Wiklander {
597062e3d01SJens Wiklander 	bigint_binary_mod(dest, op1, op2, n, mbedtls_mpi_mul_mpi);
598062e3d01SJens Wiklander }
599062e3d01SJens Wiklander 
600062e3d01SJens Wiklander void TEE_BigIntSquareMod(TEE_BigInt *dest, const TEE_BigInt *op,
601062e3d01SJens Wiklander 			 const TEE_BigInt *n)
602062e3d01SJens Wiklander {
603062e3d01SJens Wiklander 	TEE_BigIntMulMod(dest, op, op, n);
604062e3d01SJens Wiklander }
605062e3d01SJens Wiklander 
606062e3d01SJens Wiklander void TEE_BigIntInvMod(TEE_BigInt *dest, const TEE_BigInt *op,
607062e3d01SJens Wiklander 		      const TEE_BigInt *n)
608062e3d01SJens Wiklander {
609062e3d01SJens Wiklander 	mbedtls_mpi mpi_dest;
610062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
611062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
612062e3d01SJens Wiklander 	mbedtls_mpi *pop = &mpi_op;
613062e3d01SJens Wiklander 
6145bb4e062SJens Wiklander 	if (TEE_BigIntCmpS32(n, 2) < 0 || TEE_BigIntCmpS32(op, 0) == 0)
6155bb4e062SJens Wiklander 		API_PANIC("too small modulus or trying to invert zero");
6165bb4e062SJens Wiklander 
617062e3d01SJens Wiklander 	get_mpi(&mpi_dest, dest);
6187696ab7fSJens Wiklander 	get_mpi(&mpi_n, n);
619062e3d01SJens Wiklander 
620062e3d01SJens Wiklander 	if (op == dest)
621062e3d01SJens Wiklander 		pop = &mpi_dest;
622062e3d01SJens Wiklander 	else
6237696ab7fSJens Wiklander 		get_mpi(&mpi_op, op);
624062e3d01SJens Wiklander 
625062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_inv_mod(&mpi_dest, pop, &mpi_n));
626062e3d01SJens Wiklander 
6277696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dest, dest));
6287696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dest);
6297696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_n);
630062e3d01SJens Wiklander 	if (pop == &mpi_op)
6317696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op);
632062e3d01SJens Wiklander }
633062e3d01SJens Wiklander 
634062e3d01SJens Wiklander bool TEE_BigIntRelativePrime(const TEE_BigInt *op1, const TEE_BigInt *op2)
635062e3d01SJens Wiklander {
636062e3d01SJens Wiklander 	bool rc;
637062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
638062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
639062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
640062e3d01SJens Wiklander 	mbedtls_mpi gcd;
641062e3d01SJens Wiklander 
6427696ab7fSJens Wiklander 	get_mpi(&mpi_op1, op1);
643062e3d01SJens Wiklander 
644062e3d01SJens Wiklander 	if (op2 == op1)
645062e3d01SJens Wiklander 		pop2 = &mpi_op1;
646062e3d01SJens Wiklander 	else
6477696ab7fSJens Wiklander 		get_mpi(&mpi_op2, op2);
648062e3d01SJens Wiklander 
649062e3d01SJens Wiklander 	get_mpi(&gcd, NULL);
650062e3d01SJens Wiklander 
651062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_gcd(&gcd, &mpi_op1, &mpi_op2));
652062e3d01SJens Wiklander 
653062e3d01SJens Wiklander 	rc = !mbedtls_mpi_cmp_int(&gcd, 1);
654062e3d01SJens Wiklander 
6557696ab7fSJens Wiklander 	mbedtls_mpi_free(&gcd);
6567696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op1);
657062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
6587696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op2);
659062e3d01SJens Wiklander 
660062e3d01SJens Wiklander 	return rc;
661062e3d01SJens Wiklander }
662062e3d01SJens Wiklander 
663062e3d01SJens Wiklander static bool mpi_is_odd(mbedtls_mpi *x)
664062e3d01SJens Wiklander {
665062e3d01SJens Wiklander 	return mbedtls_mpi_get_bit(x, 0);
666062e3d01SJens Wiklander }
667062e3d01SJens Wiklander 
668062e3d01SJens Wiklander static bool mpi_is_even(mbedtls_mpi *x)
669062e3d01SJens Wiklander {
670062e3d01SJens Wiklander 	return !mpi_is_odd(x);
671062e3d01SJens Wiklander }
672062e3d01SJens Wiklander 
673062e3d01SJens Wiklander /*
674062e3d01SJens Wiklander  * Based on libmpa implementation __mpa_egcd(), modified to work with MPI
675062e3d01SJens Wiklander  * instead.
676062e3d01SJens Wiklander  */
677062e3d01SJens Wiklander static void mpi_egcd(mbedtls_mpi *gcd, mbedtls_mpi *a, mbedtls_mpi *b,
678062e3d01SJens Wiklander 		     mbedtls_mpi *x_in, mbedtls_mpi *y_in)
679062e3d01SJens Wiklander {
680062e3d01SJens Wiklander 	mbedtls_mpi_uint k;
681062e3d01SJens Wiklander 	mbedtls_mpi A;
682062e3d01SJens Wiklander 	mbedtls_mpi B;
683062e3d01SJens Wiklander 	mbedtls_mpi C;
684062e3d01SJens Wiklander 	mbedtls_mpi D;
685062e3d01SJens Wiklander 	mbedtls_mpi x;
686062e3d01SJens Wiklander 	mbedtls_mpi y;
687062e3d01SJens Wiklander 	mbedtls_mpi u;
688062e3d01SJens Wiklander 
689062e3d01SJens Wiklander 	get_mpi(&A, NULL);
690062e3d01SJens Wiklander 	get_mpi(&B, NULL);
691062e3d01SJens Wiklander 	get_mpi(&C, NULL);
692062e3d01SJens Wiklander 	get_mpi(&D, NULL);
693062e3d01SJens Wiklander 	get_mpi(&x, NULL);
694062e3d01SJens Wiklander 	get_mpi(&y, NULL);
695062e3d01SJens Wiklander 	get_mpi(&u, NULL);
696062e3d01SJens Wiklander 
697062e3d01SJens Wiklander 	/* have y < x from assumption */
698062e3d01SJens Wiklander 	if (!mbedtls_mpi_cmp_int(y_in, 0)) {
699062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_lset(a, 1));
700062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_lset(b, 0));
701062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_copy(gcd, x_in));
702062e3d01SJens Wiklander 		goto out;
703062e3d01SJens Wiklander 	}
704062e3d01SJens Wiklander 
705062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&x, x_in));
706062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&y, y_in));
707062e3d01SJens Wiklander 
708062e3d01SJens Wiklander 	k = 0;
709062e3d01SJens Wiklander 	while (mpi_is_even(&x) && mpi_is_even(&y)) {
710062e3d01SJens Wiklander 		k++;
711062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&x, 1));
712062e3d01SJens Wiklander 		MPI_CHECK(mbedtls_mpi_shift_r(&y, 1));
713062e3d01SJens Wiklander 	}
714062e3d01SJens Wiklander 
715062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&u, &x));
716062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(gcd, &y));
717062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&A, 1));
718062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&B, 0));
719062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&C, 0));
720062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_lset(&D, 1));
721062e3d01SJens Wiklander 
722062e3d01SJens Wiklander 	while (mbedtls_mpi_cmp_int(&u, 0)) {
723062e3d01SJens Wiklander 		while (mpi_is_even(&u)) {
724062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&u, 1));
725062e3d01SJens Wiklander 			if (mpi_is_odd(&A) || mpi_is_odd(&B)) {
726062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_add_mpi(&A, &A, &y));
727062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &x));
728062e3d01SJens Wiklander 			}
729062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&A, 1));
730062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&B, 1));
731062e3d01SJens Wiklander 		}
732062e3d01SJens Wiklander 
733062e3d01SJens Wiklander 		while (mpi_is_even(gcd)) {
734062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(gcd, 1));
735062e3d01SJens Wiklander 			if (mpi_is_odd(&C) || mpi_is_odd(&D)) {
736062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_add_mpi(&C, &C, &y));
737062e3d01SJens Wiklander 				MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &x));
738062e3d01SJens Wiklander 			}
739062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&C, 1));
740062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_shift_r(&D, 1));
741062e3d01SJens Wiklander 
742062e3d01SJens Wiklander 		}
743062e3d01SJens Wiklander 
744062e3d01SJens Wiklander 		if (mbedtls_mpi_cmp_mpi(&u, gcd) >= 0) {
745062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&u, &u, gcd));
746062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&A, &A, &C));
747062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&B, &B, &D));
748062e3d01SJens Wiklander 		} else {
749062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(gcd, gcd, &u));
750062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&C, &C, &A));
751062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_sub_mpi(&D, &D, &B));
752062e3d01SJens Wiklander 		}
753062e3d01SJens Wiklander 	}
754062e3d01SJens Wiklander 
755062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(a, &C));
756062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(b, &D));
757062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_shift_l(gcd, k));
758062e3d01SJens Wiklander 
759062e3d01SJens Wiklander out:
7607696ab7fSJens Wiklander 	mbedtls_mpi_free(&A);
7617696ab7fSJens Wiklander 	mbedtls_mpi_free(&B);
7627696ab7fSJens Wiklander 	mbedtls_mpi_free(&C);
7637696ab7fSJens Wiklander 	mbedtls_mpi_free(&D);
7647696ab7fSJens Wiklander 	mbedtls_mpi_free(&x);
7657696ab7fSJens Wiklander 	mbedtls_mpi_free(&y);
7667696ab7fSJens Wiklander 	mbedtls_mpi_free(&u);
767062e3d01SJens Wiklander }
768062e3d01SJens Wiklander 
769062e3d01SJens Wiklander void TEE_BigIntComputeExtendedGcd(TEE_BigInt *gcd, TEE_BigInt *u,
770062e3d01SJens Wiklander 				  TEE_BigInt *v, const TEE_BigInt *op1,
771062e3d01SJens Wiklander 				  const TEE_BigInt *op2)
772062e3d01SJens Wiklander {
773062e3d01SJens Wiklander 	mbedtls_mpi mpi_gcd_res;
774062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
775062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
776062e3d01SJens Wiklander 	mbedtls_mpi *pop2 = &mpi_op2;
777062e3d01SJens Wiklander 
778062e3d01SJens Wiklander 	get_mpi(&mpi_gcd_res, gcd);
7797696ab7fSJens Wiklander 	get_mpi(&mpi_op1, op1);
780062e3d01SJens Wiklander 
781062e3d01SJens Wiklander 	if (op2 == op1)
782062e3d01SJens Wiklander 		pop2 = &mpi_op1;
783062e3d01SJens Wiklander 	else
7847696ab7fSJens Wiklander 		get_mpi(&mpi_op2, op2);
785062e3d01SJens Wiklander 
786062e3d01SJens Wiklander 	if (!u && !v) {
787b6fa905fSJens Wiklander 		MPI_CHECK(mbedtls_mpi_gcd(&mpi_gcd_res, &mpi_op1, pop2));
788062e3d01SJens Wiklander 	} else {
789062e3d01SJens Wiklander 		mbedtls_mpi mpi_u;
790062e3d01SJens Wiklander 		mbedtls_mpi mpi_v;
791062e3d01SJens Wiklander 		int8_t s1 = mpi_op1.s;
792062e3d01SJens Wiklander 		int8_t s2 = pop2->s;
793062e3d01SJens Wiklander 		int cmp;
794062e3d01SJens Wiklander 
795062e3d01SJens Wiklander 		mpi_op1.s = 1;
796062e3d01SJens Wiklander 		pop2->s = 1;
797062e3d01SJens Wiklander 
798062e3d01SJens Wiklander 		get_mpi(&mpi_u, u);
799062e3d01SJens Wiklander 		get_mpi(&mpi_v, v);
800062e3d01SJens Wiklander 
801062e3d01SJens Wiklander 		cmp = mbedtls_mpi_cmp_abs(&mpi_op1, pop2);
802062e3d01SJens Wiklander 		if (cmp == 0) {
803062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_copy(&mpi_gcd_res, &mpi_op1));
804062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_lset(&mpi_u, 1));
805062e3d01SJens Wiklander 			MPI_CHECK(mbedtls_mpi_lset(&mpi_v, 0));
806062e3d01SJens Wiklander 		} else if (cmp > 0) {
807062e3d01SJens Wiklander 			mpi_egcd(&mpi_gcd_res, &mpi_u, &mpi_v, &mpi_op1, pop2);
808062e3d01SJens Wiklander 		} else {
809062e3d01SJens Wiklander 			mpi_egcd(&mpi_gcd_res, &mpi_v, &mpi_u, pop2, &mpi_op1);
810062e3d01SJens Wiklander 		}
811062e3d01SJens Wiklander 
812062e3d01SJens Wiklander 		mpi_u.s *= s1;
813062e3d01SJens Wiklander 		mpi_v.s *= s2;
814062e3d01SJens Wiklander 
8157696ab7fSJens Wiklander 		MPI_CHECK(copy_mpi_to_bigint(&mpi_u, u));
8167696ab7fSJens Wiklander 		MPI_CHECK(copy_mpi_to_bigint(&mpi_v, v));
8177696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_u);
8187696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_v);
819062e3d01SJens Wiklander 	}
820062e3d01SJens Wiklander 
8217696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_gcd_res, gcd));
8227696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_gcd_res);
8237696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op1);
824062e3d01SJens Wiklander 	if (pop2 == &mpi_op2)
8257696ab7fSJens Wiklander 		mbedtls_mpi_free(&mpi_op2);
826062e3d01SJens Wiklander }
827062e3d01SJens Wiklander 
828062e3d01SJens Wiklander static int rng_read(void *ignored __unused, unsigned char *buf, size_t blen)
829062e3d01SJens Wiklander {
8302c028fdeSJerome Forissier 	if (_utee_cryp_random_number_generate(buf, blen))
831062e3d01SJens Wiklander 		return MBEDTLS_ERR_MPI_FILE_IO_ERROR;
832062e3d01SJens Wiklander 	return 0;
833062e3d01SJens Wiklander }
834062e3d01SJens Wiklander 
835062e3d01SJens Wiklander int32_t TEE_BigIntIsProbablePrime(const TEE_BigInt *op,
836062e3d01SJens Wiklander 				  uint32_t confidenceLevel __unused)
837062e3d01SJens Wiklander {
838062e3d01SJens Wiklander 	int rc;
839062e3d01SJens Wiklander 	mbedtls_mpi mpi_op;
840062e3d01SJens Wiklander 
8417696ab7fSJens Wiklander 	get_mpi(&mpi_op, op);
842062e3d01SJens Wiklander 
843062e3d01SJens Wiklander 	rc = mbedtls_mpi_is_prime(&mpi_op, rng_read, NULL);
844062e3d01SJens Wiklander 
8457696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op);
846062e3d01SJens Wiklander 
847062e3d01SJens Wiklander 	if (rc)
848062e3d01SJens Wiklander 		return 0;
849062e3d01SJens Wiklander 
850062e3d01SJens Wiklander 	return 1;
851062e3d01SJens Wiklander }
852062e3d01SJens Wiklander 
853062e3d01SJens Wiklander /*
854062e3d01SJens Wiklander  * Not so fast FMM implementation based on the normal big int functions.
855062e3d01SJens Wiklander  *
856062e3d01SJens Wiklander  * Note that these functions (along with all the other functions in this
857062e3d01SJens Wiklander  * file) only are used directly by the TA doing bigint arithmetics on its
858062e3d01SJens Wiklander  * own. Performance of RSA operations in TEE Internal API are not affected
859062e3d01SJens Wiklander  * by this.
860062e3d01SJens Wiklander  */
861fe03ed8bSJens Wiklander void TEE_BigIntInitFMM(TEE_BigIntFMM *bigIntFMM, size_t len)
862062e3d01SJens Wiklander {
863062e3d01SJens Wiklander 	TEE_BigIntInit(bigIntFMM, len);
864062e3d01SJens Wiklander }
865062e3d01SJens Wiklander 
866fe03ed8bSJens Wiklander void __GP11_TEE_BigIntInitFMM(TEE_BigIntFMM *bigIntFMM, uint32_t len)
867fe03ed8bSJens Wiklander {
868fe03ed8bSJens Wiklander 	TEE_BigIntInitFMM(bigIntFMM, len);
869fe03ed8bSJens Wiklander }
870fe03ed8bSJens Wiklander 
871062e3d01SJens Wiklander void TEE_BigIntInitFMMContext(TEE_BigIntFMMContext *context __unused,
872fe03ed8bSJens Wiklander 			      size_t len __unused,
873062e3d01SJens Wiklander 			      const TEE_BigInt *modulus __unused)
874062e3d01SJens Wiklander {
875062e3d01SJens Wiklander }
876062e3d01SJens Wiklander 
877fe03ed8bSJens Wiklander void __GP11_TEE_BigIntInitFMMContext(TEE_BigIntFMMContext *context,
878fe03ed8bSJens Wiklander 				     uint32_t len, const TEE_BigInt *modulus)
879fe03ed8bSJens Wiklander {
880fe03ed8bSJens Wiklander 	TEE_BigIntInitFMMContext(context, len, modulus);
881fe03ed8bSJens Wiklander }
882fe03ed8bSJens Wiklander 
883fe03ed8bSJens Wiklander TEE_Result TEE_BigIntInitFMMContext1(TEE_BigIntFMMContext *context __unused,
884fe03ed8bSJens Wiklander 				     size_t len __unused,
885fe03ed8bSJens Wiklander 				     const TEE_BigInt *modulus __unused)
886fe03ed8bSJens Wiklander {
887fe03ed8bSJens Wiklander 	return TEE_SUCCESS;
888fe03ed8bSJens Wiklander }
889fe03ed8bSJens Wiklander 
890fe03ed8bSJens Wiklander size_t TEE_BigIntFMMSizeInU32(size_t modulusSizeInBits)
891062e3d01SJens Wiklander {
892062e3d01SJens Wiklander 	return TEE_BigIntSizeInU32(modulusSizeInBits);
893062e3d01SJens Wiklander }
894062e3d01SJens Wiklander 
895fe03ed8bSJens Wiklander uint32_t __GP11_TEE_BigIntFMMSizeInU32(uint32_t modulusSizeInBits)
896fe03ed8bSJens Wiklander {
897fe03ed8bSJens Wiklander 	return TEE_BigIntFMMSizeInU32(modulusSizeInBits);
898fe03ed8bSJens Wiklander }
899fe03ed8bSJens Wiklander 
900fe03ed8bSJens Wiklander size_t TEE_BigIntFMMContextSizeInU32(size_t modulusSizeInBits __unused)
901062e3d01SJens Wiklander {
902062e3d01SJens Wiklander 	/* Return something larger than 0 to keep malloc() and friends happy */
903062e3d01SJens Wiklander 	return 1;
904062e3d01SJens Wiklander }
905062e3d01SJens Wiklander 
906fe03ed8bSJens Wiklander uint32_t __GP11_TEE_BigIntFMMContextSizeInU32(uint32_t modulusSizeInBits)
907fe03ed8bSJens Wiklander {
908fe03ed8bSJens Wiklander 	return TEE_BigIntFMMContextSizeInU32(modulusSizeInBits);
909fe03ed8bSJens Wiklander }
910fe03ed8bSJens Wiklander 
911062e3d01SJens Wiklander void TEE_BigIntConvertToFMM(TEE_BigIntFMM *dest, const TEE_BigInt *src,
912062e3d01SJens Wiklander 			    const TEE_BigInt *n,
913062e3d01SJens Wiklander 			    const TEE_BigIntFMMContext *context __unused)
914062e3d01SJens Wiklander {
915062e3d01SJens Wiklander 	TEE_BigIntMod(dest, src, n);
916062e3d01SJens Wiklander }
917062e3d01SJens Wiklander 
918062e3d01SJens Wiklander void TEE_BigIntConvertFromFMM(TEE_BigInt *dest, const TEE_BigIntFMM *src,
919062e3d01SJens Wiklander 			      const TEE_BigInt *n __unused,
920062e3d01SJens Wiklander 			      const TEE_BigIntFMMContext *context __unused)
921062e3d01SJens Wiklander {
922062e3d01SJens Wiklander 	mbedtls_mpi mpi_dst;
923062e3d01SJens Wiklander 	mbedtls_mpi mpi_src;
924062e3d01SJens Wiklander 
925062e3d01SJens Wiklander 	get_mpi(&mpi_dst, dest);
9267696ab7fSJens Wiklander 	get_mpi(&mpi_src, src);
927062e3d01SJens Wiklander 
928062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_copy(&mpi_dst, &mpi_src));
929062e3d01SJens Wiklander 
9307696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dst, dest));
9317696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dst);
9327696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_src);
933062e3d01SJens Wiklander }
934062e3d01SJens Wiklander 
935062e3d01SJens Wiklander void TEE_BigIntComputeFMM(TEE_BigIntFMM *dest, const TEE_BigIntFMM *op1,
936062e3d01SJens Wiklander 			  const TEE_BigIntFMM *op2, const TEE_BigInt *n,
937062e3d01SJens Wiklander 			  const TEE_BigIntFMMContext *context __unused)
938062e3d01SJens Wiklander {
939062e3d01SJens Wiklander 	mbedtls_mpi mpi_dst;
940062e3d01SJens Wiklander 	mbedtls_mpi mpi_op1;
941062e3d01SJens Wiklander 	mbedtls_mpi mpi_op2;
942062e3d01SJens Wiklander 	mbedtls_mpi mpi_n;
943062e3d01SJens Wiklander 	mbedtls_mpi mpi_t;
944062e3d01SJens Wiklander 
945062e3d01SJens Wiklander 	get_mpi(&mpi_dst, dest);
9467696ab7fSJens Wiklander 	get_mpi(&mpi_op1, op1);
9477696ab7fSJens Wiklander 	get_mpi(&mpi_op2, op2);
9487696ab7fSJens Wiklander 	get_mpi(&mpi_n, n);
949062e3d01SJens Wiklander 	get_mpi(&mpi_t, NULL);
950062e3d01SJens Wiklander 
951062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mul_mpi(&mpi_t, &mpi_op1, &mpi_op2));
952062e3d01SJens Wiklander 	MPI_CHECK(mbedtls_mpi_mod_mpi(&mpi_dst, &mpi_t, &mpi_n));
953062e3d01SJens Wiklander 
9547696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_t);
9557696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_n);
9567696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op2);
9577696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_op1);
9587696ab7fSJens Wiklander 	MPI_CHECK(copy_mpi_to_bigint(&mpi_dst, dest));
9597696ab7fSJens Wiklander 	mbedtls_mpi_free(&mpi_dst);
960062e3d01SJens Wiklander }
961