18c2ecf20Sopenharmony_ci/* mpi-add.c  -  MPI functions
28c2ecf20Sopenharmony_ci * Copyright (C) 1994, 1996, 1998, 2001, 2002,
38c2ecf20Sopenharmony_ci *               2003 Free Software Foundation, Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file is part of Libgcrypt.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Note: This code is heavily based on the GNU MP Library.
88c2ecf20Sopenharmony_ci *	 Actually it's the same code with only minor changes in the
98c2ecf20Sopenharmony_ci *	 way the data is stored; this is to support the abstraction
108c2ecf20Sopenharmony_ci *	 of an optional secure memory allocation which may be used
118c2ecf20Sopenharmony_ci *	 to avoid revealing of sensitive data due to paging etc.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "mpi-internal.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/****************
178c2ecf20Sopenharmony_ci * Add the unsigned integer V to the mpi-integer U and store the
188c2ecf20Sopenharmony_ci * result in W. U and V may be the same.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_civoid mpi_add_ui(MPI w, MPI u, unsigned long v)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	mpi_ptr_t wp, up;
238c2ecf20Sopenharmony_ci	mpi_size_t usize, wsize;
248c2ecf20Sopenharmony_ci	int usign, wsign;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	usize = u->nlimbs;
278c2ecf20Sopenharmony_ci	usign = u->sign;
288c2ecf20Sopenharmony_ci	wsign = 0;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* If not space for W (and possible carry), increase space.  */
318c2ecf20Sopenharmony_ci	wsize = usize + 1;
328c2ecf20Sopenharmony_ci	if (w->alloced < wsize)
338c2ecf20Sopenharmony_ci		mpi_resize(w, wsize);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* These must be after realloc (U may be the same as W).  */
368c2ecf20Sopenharmony_ci	up = u->d;
378c2ecf20Sopenharmony_ci	wp = w->d;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!usize) {  /* simple */
408c2ecf20Sopenharmony_ci		wp[0] = v;
418c2ecf20Sopenharmony_ci		wsize = v ? 1:0;
428c2ecf20Sopenharmony_ci	} else if (!usign) {  /* mpi is not negative */
438c2ecf20Sopenharmony_ci		mpi_limb_t cy;
448c2ecf20Sopenharmony_ci		cy = mpihelp_add_1(wp, up, usize, v);
458c2ecf20Sopenharmony_ci		wp[usize] = cy;
468c2ecf20Sopenharmony_ci		wsize = usize + cy;
478c2ecf20Sopenharmony_ci	} else {
488c2ecf20Sopenharmony_ci		/* The signs are different.  Need exact comparison to determine
498c2ecf20Sopenharmony_ci		 * which operand to subtract from which.
508c2ecf20Sopenharmony_ci		 */
518c2ecf20Sopenharmony_ci		if (usize == 1 && up[0] < v) {
528c2ecf20Sopenharmony_ci			wp[0] = v - up[0];
538c2ecf20Sopenharmony_ci			wsize = 1;
548c2ecf20Sopenharmony_ci		} else {
558c2ecf20Sopenharmony_ci			mpihelp_sub_1(wp, up, usize, v);
568c2ecf20Sopenharmony_ci			/* Size can decrease with at most one limb. */
578c2ecf20Sopenharmony_ci			wsize = usize - (wp[usize-1] == 0);
588c2ecf20Sopenharmony_ci			wsign = 1;
598c2ecf20Sopenharmony_ci		}
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	w->nlimbs = wsize;
638c2ecf20Sopenharmony_ci	w->sign   = wsign;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_civoid mpi_add(MPI w, MPI u, MPI v)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	mpi_ptr_t wp, up, vp;
708c2ecf20Sopenharmony_ci	mpi_size_t usize, vsize, wsize;
718c2ecf20Sopenharmony_ci	int usign, vsign, wsign;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
748c2ecf20Sopenharmony_ci		usize = v->nlimbs;
758c2ecf20Sopenharmony_ci		usign = v->sign;
768c2ecf20Sopenharmony_ci		vsize = u->nlimbs;
778c2ecf20Sopenharmony_ci		vsign = u->sign;
788c2ecf20Sopenharmony_ci		wsize = usize + 1;
798c2ecf20Sopenharmony_ci		RESIZE_IF_NEEDED(w, wsize);
808c2ecf20Sopenharmony_ci		/* These must be after realloc (u or v may be the same as w).  */
818c2ecf20Sopenharmony_ci		up = v->d;
828c2ecf20Sopenharmony_ci		vp = u->d;
838c2ecf20Sopenharmony_ci	} else {
848c2ecf20Sopenharmony_ci		usize = u->nlimbs;
858c2ecf20Sopenharmony_ci		usign = u->sign;
868c2ecf20Sopenharmony_ci		vsize = v->nlimbs;
878c2ecf20Sopenharmony_ci		vsign = v->sign;
888c2ecf20Sopenharmony_ci		wsize = usize + 1;
898c2ecf20Sopenharmony_ci		RESIZE_IF_NEEDED(w, wsize);
908c2ecf20Sopenharmony_ci		/* These must be after realloc (u or v may be the same as w).  */
918c2ecf20Sopenharmony_ci		up = u->d;
928c2ecf20Sopenharmony_ci		vp = v->d;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci	wp = w->d;
958c2ecf20Sopenharmony_ci	wsign = 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!vsize) {  /* simple */
988c2ecf20Sopenharmony_ci		MPN_COPY(wp, up, usize);
998c2ecf20Sopenharmony_ci		wsize = usize;
1008c2ecf20Sopenharmony_ci		wsign = usign;
1018c2ecf20Sopenharmony_ci	} else if (usign != vsign) { /* different sign */
1028c2ecf20Sopenharmony_ci		/* This test is right since USIZE >= VSIZE */
1038c2ecf20Sopenharmony_ci		if (usize != vsize) {
1048c2ecf20Sopenharmony_ci			mpihelp_sub(wp, up, usize, vp, vsize);
1058c2ecf20Sopenharmony_ci			wsize = usize;
1068c2ecf20Sopenharmony_ci			MPN_NORMALIZE(wp, wsize);
1078c2ecf20Sopenharmony_ci			wsign = usign;
1088c2ecf20Sopenharmony_ci		} else if (mpihelp_cmp(up, vp, usize) < 0) {
1098c2ecf20Sopenharmony_ci			mpihelp_sub_n(wp, vp, up, usize);
1108c2ecf20Sopenharmony_ci			wsize = usize;
1118c2ecf20Sopenharmony_ci			MPN_NORMALIZE(wp, wsize);
1128c2ecf20Sopenharmony_ci			if (!usign)
1138c2ecf20Sopenharmony_ci				wsign = 1;
1148c2ecf20Sopenharmony_ci		} else {
1158c2ecf20Sopenharmony_ci			mpihelp_sub_n(wp, up, vp, usize);
1168c2ecf20Sopenharmony_ci			wsize = usize;
1178c2ecf20Sopenharmony_ci			MPN_NORMALIZE(wp, wsize);
1188c2ecf20Sopenharmony_ci			if (usign)
1198c2ecf20Sopenharmony_ci				wsign = 1;
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci	} else { /* U and V have same sign. Add them. */
1228c2ecf20Sopenharmony_ci		mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
1238c2ecf20Sopenharmony_ci		wp[usize] = cy;
1248c2ecf20Sopenharmony_ci		wsize = usize + cy;
1258c2ecf20Sopenharmony_ci		if (usign)
1268c2ecf20Sopenharmony_ci			wsign = 1;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	w->nlimbs = wsize;
1308c2ecf20Sopenharmony_ci	w->sign = wsign;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_add);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_civoid mpi_sub(MPI w, MPI u, MPI v)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	MPI vv = mpi_copy(v);
1378c2ecf20Sopenharmony_ci	vv->sign = !vv->sign;
1388c2ecf20Sopenharmony_ci	mpi_add(w, u, vv);
1398c2ecf20Sopenharmony_ci	mpi_free(vv);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_civoid mpi_addm(MPI w, MPI u, MPI v, MPI m)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	mpi_add(w, u, v);
1468c2ecf20Sopenharmony_ci	mpi_mod(w, w, m);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_addm);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_civoid mpi_subm(MPI w, MPI u, MPI v, MPI m)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	mpi_sub(w, u, v);
1538c2ecf20Sopenharmony_ci	mpi_mod(w, w, m);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_subm);
156