xref: /linux/lib/crypto/mpi/mpi-add.c (revision 55d0969c451159cff86949b38c39171cab962069)
1 /* mpi-add.c  -  MPI functions
2  * Copyright (C) 1994, 1996, 1998, 2001, 2002,
3  *               2003 Free Software Foundation, Inc.
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Note: This code is heavily based on the GNU MP Library.
8  *	 Actually it's the same code with only minor changes in the
9  *	 way the data is stored; this is to support the abstraction
10  *	 of an optional secure memory allocation which may be used
11  *	 to avoid revealing of sensitive data due to paging etc.
12  */
13 
14 #include "mpi-internal.h"
15 
16 int mpi_add(MPI w, MPI u, MPI v)
17 {
18 	mpi_ptr_t wp, up, vp;
19 	mpi_size_t usize, vsize, wsize;
20 	int usign, vsign, wsign;
21 	int err;
22 
23 	if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
24 		usize = v->nlimbs;
25 		usign = v->sign;
26 		vsize = u->nlimbs;
27 		vsign = u->sign;
28 		wsize = usize + 1;
29 		err = RESIZE_IF_NEEDED(w, wsize);
30 		if (err)
31 			return err;
32 		/* These must be after realloc (u or v may be the same as w).  */
33 		up = v->d;
34 		vp = u->d;
35 	} else {
36 		usize = u->nlimbs;
37 		usign = u->sign;
38 		vsize = v->nlimbs;
39 		vsign = v->sign;
40 		wsize = usize + 1;
41 		err = RESIZE_IF_NEEDED(w, wsize);
42 		if (err)
43 			return err;
44 		/* These must be after realloc (u or v may be the same as w).  */
45 		up = u->d;
46 		vp = v->d;
47 	}
48 	wp = w->d;
49 	wsign = 0;
50 
51 	if (!vsize) {  /* simple */
52 		MPN_COPY(wp, up, usize);
53 		wsize = usize;
54 		wsign = usign;
55 	} else if (usign != vsign) { /* different sign */
56 		/* This test is right since USIZE >= VSIZE */
57 		if (usize != vsize) {
58 			mpihelp_sub(wp, up, usize, vp, vsize);
59 			wsize = usize;
60 			MPN_NORMALIZE(wp, wsize);
61 			wsign = usign;
62 		} else if (mpihelp_cmp(up, vp, usize) < 0) {
63 			mpihelp_sub_n(wp, vp, up, usize);
64 			wsize = usize;
65 			MPN_NORMALIZE(wp, wsize);
66 			if (!usign)
67 				wsign = 1;
68 		} else {
69 			mpihelp_sub_n(wp, up, vp, usize);
70 			wsize = usize;
71 			MPN_NORMALIZE(wp, wsize);
72 			if (usign)
73 				wsign = 1;
74 		}
75 	} else { /* U and V have same sign. Add them. */
76 		mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
77 		wp[usize] = cy;
78 		wsize = usize + cy;
79 		if (usign)
80 			wsign = 1;
81 	}
82 
83 	w->nlimbs = wsize;
84 	w->sign = wsign;
85 	return 0;
86 }
87 EXPORT_SYMBOL_GPL(mpi_add);
88 
89 int mpi_sub(MPI w, MPI u, MPI v)
90 {
91 	int err;
92 	MPI vv;
93 
94 	vv = mpi_copy(v);
95 	if (!vv)
96 		return -ENOMEM;
97 
98 	vv->sign = !vv->sign;
99 	err = mpi_add(w, u, vv);
100 	mpi_free(vv);
101 
102 	return err;
103 }
104 EXPORT_SYMBOL_GPL(mpi_sub);
105 
106 int mpi_addm(MPI w, MPI u, MPI v, MPI m)
107 {
108 	return mpi_add(w, u, v) ?:
109 	       mpi_mod(w, w, m);
110 }
111 EXPORT_SYMBOL_GPL(mpi_addm);
112 
113 int mpi_subm(MPI w, MPI u, MPI v, MPI m)
114 {
115 	return mpi_sub(w, u, v) ?:
116 	       mpi_mod(w, w, m);
117 }
118 EXPORT_SYMBOL_GPL(mpi_subm);
119