xref: /linux/lib/crypto/mpi/mpi-add.c (revision 13150742b09e720fdf021de14cd2b98b37415a89)
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 <linux/export.h>
15 
16 #include "mpi-internal.h"
17 
mpi_add(MPI w,MPI u,MPI v)18 int mpi_add(MPI w, MPI u, MPI v)
19 {
20 	mpi_ptr_t wp, up, vp;
21 	mpi_size_t usize, vsize, wsize;
22 	int usign, vsign, wsign;
23 	int err;
24 
25 	if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
26 		usize = v->nlimbs;
27 		usign = v->sign;
28 		vsize = u->nlimbs;
29 		vsign = u->sign;
30 		wsize = usize + 1;
31 		err = RESIZE_IF_NEEDED(w, wsize);
32 		if (err)
33 			return err;
34 		/* These must be after realloc (u or v may be the same as w).  */
35 		up = v->d;
36 		vp = u->d;
37 	} else {
38 		usize = u->nlimbs;
39 		usign = u->sign;
40 		vsize = v->nlimbs;
41 		vsign = v->sign;
42 		wsize = usize + 1;
43 		err = RESIZE_IF_NEEDED(w, wsize);
44 		if (err)
45 			return err;
46 		/* These must be after realloc (u or v may be the same as w).  */
47 		up = u->d;
48 		vp = v->d;
49 	}
50 	wp = w->d;
51 	wsign = 0;
52 
53 	if (!vsize) {  /* simple */
54 		MPN_COPY(wp, up, usize);
55 		wsize = usize;
56 		wsign = usign;
57 	} else if (usign != vsign) { /* different sign */
58 		/* This test is right since USIZE >= VSIZE */
59 		if (usize != vsize) {
60 			mpihelp_sub(wp, up, usize, vp, vsize);
61 			wsize = usize;
62 			MPN_NORMALIZE(wp, wsize);
63 			wsign = usign;
64 		} else if (mpihelp_cmp(up, vp, usize) < 0) {
65 			mpihelp_sub_n(wp, vp, up, usize);
66 			wsize = usize;
67 			MPN_NORMALIZE(wp, wsize);
68 			if (!usign)
69 				wsign = 1;
70 		} else {
71 			mpihelp_sub_n(wp, up, vp, usize);
72 			wsize = usize;
73 			MPN_NORMALIZE(wp, wsize);
74 			if (usign)
75 				wsign = 1;
76 		}
77 	} else { /* U and V have same sign. Add them. */
78 		mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
79 		wp[usize] = cy;
80 		wsize = usize + cy;
81 		if (usign)
82 			wsign = 1;
83 	}
84 
85 	w->nlimbs = wsize;
86 	w->sign = wsign;
87 	return 0;
88 }
89 EXPORT_SYMBOL_GPL(mpi_add);
90 
mpi_sub(MPI w,MPI u,MPI v)91 int mpi_sub(MPI w, MPI u, MPI v)
92 {
93 	int err;
94 	MPI vv;
95 
96 	vv = mpi_copy(v);
97 	if (!vv)
98 		return -ENOMEM;
99 
100 	vv->sign = !vv->sign;
101 	err = mpi_add(w, u, vv);
102 	mpi_free(vv);
103 
104 	return err;
105 }
106 EXPORT_SYMBOL_GPL(mpi_sub);
107 
mpi_addm(MPI w,MPI u,MPI v,MPI m)108 int mpi_addm(MPI w, MPI u, MPI v, MPI m)
109 {
110 	return mpi_add(w, u, v) ?:
111 	       mpi_mod(w, w, m);
112 }
113 EXPORT_SYMBOL_GPL(mpi_addm);
114 
mpi_subm(MPI w,MPI u,MPI v,MPI m)115 int mpi_subm(MPI w, MPI u, MPI v, MPI m)
116 {
117 	return mpi_sub(w, u, v) ?:
118 	       mpi_mod(w, w, m);
119 }
120 EXPORT_SYMBOL_GPL(mpi_subm);
121