1
2 /***************************************************************************
3 *
4 Copyright 2012 CertiVox IOM Ltd. *
5 *
6 This file is part of CertiVox MIRACL Crypto SDK. *
7 *
8 The CertiVox MIRACL Crypto SDK provides developers with an *
9 extensive and efficient set of cryptographic functions. *
10 For further information about its features and functionalities please *
11 refer to http://www.certivox.com *
12 *
13 * The CertiVox MIRACL Crypto SDK is free software: you can *
14 redistribute it and/or modify it under the terms of the *
15 GNU Affero General Public License as published by the *
16 Free Software Foundation, either version 3 of the License, *
17 or (at your option) any later version. *
18 *
19 * The CertiVox MIRACL Crypto SDK is distributed in the hope *
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the *
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
22 See the GNU Affero General Public License for more details. *
23 *
24 * You should have received a copy of the GNU Affero General Public *
25 License along with CertiVox MIRACL Crypto SDK. *
26 If not, see <http://www.gnu.org/licenses/>. *
27 *
28 You can be released from the requirements of the license by purchasing *
29 a commercial license. Buying such a license is mandatory as soon as you *
30 develop commercial activities involving the CertiVox MIRACL Crypto SDK *
31 without disclosing the source code of your own applications, or shipping *
32 the CertiVox MIRACL Crypto SDK with a closed source product. *
33 *
34 ***************************************************************************/
35 /*
36 * MIRACL arithmetic routines 0 - Add and subtract routines
37 * mrarth0.c
38 *
39 */
40 #include "miracl.h"
41
mr_padd(_MIPD_ big x,big y,big z)42 void mr_padd(_MIPD_ big x,big y,big z)
43 { /* add two big numbers, z=x+y where *
44 * x and y are positive */
45 int i,lx,ly,lz,la;
46 mr_small carry,psum;
47 mr_small *gx,*gy,*gz;
48 #ifdef MR_OS_THREADS
49 miracl *mr_mip=get_mip();
50 #endif
51 lx = (int)x->len;
52 ly = (int)y->len;
53
54 if (ly>lx)
55 {
56 lz=ly;
57 la=lx;
58 if (x!=z) copy(y,z);
59 else la=ly;
60 }
61 else
62 {
63 lz=lx;
64 la=ly;
65 if (y!=z) copy(x,z);
66 else la=lx;
67 }
68 carry=0;
69 z->len=lz;
70 gx=x->w; gy=y->w; gz=z->w;
71 if (lz<mr_mip->nib || !mr_mip->check) z->len++;
72 #ifndef MR_SIMPLE_BASE
73 if (mr_mip->base==0)
74 {
75 #endif
76 for (i=0;i<la;i++)
77 { /* add by columns to length of the smaller number */
78 psum=gx[i]+gy[i]+carry;
79 if (psum>gx[i]) carry=0;
80 else if (psum<gx[i]) carry=1;
81 gz[i]=psum;
82 }
83 for (;i<lz && carry>0;i++ )
84 { /* add by columns to the length of larger number (if there is a carry) */
85 psum=gx[i]+gy[i]+carry;
86 if (psum>gx[i]) carry=0;
87 else if (psum<gx[i]) carry=1;
88 gz[i]=psum;
89 }
90 if (carry)
91 { /* carry left over - possible overflow */
92 if (mr_mip->check && i>=mr_mip->nib)
93 {
94 mr_berror(_MIPP_ MR_ERR_OVERFLOW);
95 return;
96 }
97 gz[i]=carry;
98 }
99 #ifndef MR_SIMPLE_BASE
100 }
101 else
102 {
103 for (i=0;i<la;i++)
104 { /* add by columns */
105 psum=gx[i]+gy[i]+carry;
106 carry=0;
107 if (psum>=mr_mip->base)
108 { /* set carry */
109 carry=1;
110 psum-=mr_mip->base;
111 }
112 gz[i]=psum;
113 }
114 for (;i<lz && carry>0;i++)
115 {
116 psum=gx[i]+gy[i]+carry;
117 carry=0;
118 if (psum>=mr_mip->base)
119 { /* set carry */
120 carry=1;
121 psum-=mr_mip->base;
122 }
123 gz[i]=psum;
124 }
125 if (carry)
126 { /* carry left over - possible overflow */
127 if (mr_mip->check && i>=mr_mip->nib)
128 {
129 mr_berror(_MIPP_ MR_ERR_OVERFLOW);
130 return;
131 }
132 gz[i]=carry;
133 }
134 }
135 #endif
136 if (gz[z->len-1]==0) z->len--;
137
138 }
139
mr_psub(_MIPD_ big x,big y,big z)140 void mr_psub(_MIPD_ big x,big y,big z)
141 { /* subtract two big numbers z=x-y *
142 * where x and y are positive and x>y */
143 int i,lx,ly;
144 mr_small borrow,pdiff;
145 mr_small *gx,*gy,*gz;
146 #ifdef MR_OS_THREADS
147 miracl *mr_mip=get_mip();
148 #endif
149 lx = (int)x->len;
150 ly = (int)y->len;
151 if (ly>lx)
152 {
153 mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
154 return;
155 }
156 if (y!=z) copy(x,z);
157 else ly=lx;
158 z->len=lx;
159 gx=x->w; gy=y->w; gz=z->w;
160 borrow=0;
161 #ifndef MR_SIMPLE_BASE
162 if (mr_mip->base==0)
163 {
164 #endif
165 for (i=0;i<ly || borrow>0;i++)
166 { /* subtract by columns */
167 if (i>lx)
168 {
169 mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
170 return;
171 }
172 pdiff=gx[i]-gy[i]-borrow;
173 if (pdiff<gx[i]) borrow=0;
174 else if (pdiff>gx[i]) borrow=1;
175 gz[i]=pdiff;
176 }
177 #ifndef MR_SIMPLE_BASE
178 }
179 else for (i=0;i<ly || borrow>0;i++)
180 { /* subtract by columns */
181 if (i>lx)
182 {
183 mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
184 return;
185 }
186 pdiff=gy[i]+borrow;
187 borrow=0;
188 if (gx[i]>=pdiff) pdiff=gx[i]-pdiff;
189 else
190 { /* set borrow */
191 pdiff=mr_mip->base+gx[i]-pdiff;
192 borrow=1;
193 }
194 gz[i]=pdiff;
195 }
196 #endif
197 mr_lzero(z);
198 }
199
mr_select(_MIPD_ big x,int d,big y,big z)200 static void mr_select(_MIPD_ big x,int d,big y,big z)
201 { /* perform required add or subtract operation */
202 int sx,sy,sz,jf,xgty;
203 #ifdef MR_FLASH
204 if (mr_notint(x) || mr_notint(y))
205 {
206 mr_berror(_MIPP_ MR_ERR_INT_OP);
207 return;
208 }
209 #endif
210 sx=exsign(x);
211 sy=exsign(y);
212 sz=0;
213 x->len&=MR_OBITS; /* force operands to be positive */
214 y->len&=MR_OBITS;
215 xgty=mr_compare(x,y);
216 jf=(1+sx)+(1+d*sy)/2;
217 switch (jf)
218 { /* branch according to signs of operands */
219 case 0:
220 if (xgty>=0)
221 mr_padd(_MIPP_ x,y,z);
222 else
223 mr_padd(_MIPP_ y,x,z);
224 sz=MINUS;
225 break;
226 case 1:
227 if (xgty<=0)
228 {
229 mr_psub(_MIPP_ y,x,z);
230 sz=PLUS;
231 }
232 else
233 {
234 mr_psub(_MIPP_ x,y,z);
235 sz=MINUS;
236 }
237 break;
238 case 2:
239 if (xgty>=0)
240 {
241 mr_psub(_MIPP_ x,y,z);
242 sz=PLUS;
243 }
244 else
245 {
246 mr_psub(_MIPP_ y,x,z);
247 sz=MINUS;
248 }
249 break;
250 case 3:
251 if (xgty>=0)
252 mr_padd(_MIPP_ x,y,z);
253 else
254 mr_padd(_MIPP_ y,x,z);
255 sz=PLUS;
256 break;
257 }
258 if (sz<0) z->len^=MR_MSBIT; /* set sign of result */
259 if (x!=z && sx<0) x->len^=MR_MSBIT; /* restore signs to operands */
260 if (y!=z && y!=x && sy<0) y->len^=MR_MSBIT;
261 }
262
add(_MIPD_ big x,big y,big z)263 void add(_MIPD_ big x,big y,big z)
264 { /* add two signed big numbers together z=x+y */
265 #ifdef MR_OS_THREADS
266 miracl *mr_mip=get_mip();
267 #endif
268 if (mr_mip->ERNUM) return;
269
270 MR_IN(27)
271
272 mr_select(_MIPP_ x,PLUS,y,z);
273
274 MR_OUT
275 }
276
subtract(_MIPD_ big x,big y,big z)277 void subtract(_MIPD_ big x,big y,big z)
278 { /* subtract two big signed numbers z=x-y */
279 #ifdef MR_OS_THREADS
280 miracl *mr_mip=get_mip();
281 #endif
282 if (mr_mip->ERNUM) return;
283
284 MR_IN(28)
285
286 mr_select(_MIPP_ x,MINUS,y,z);
287
288 MR_OUT
289 }
290
incr(_MIPD_ big x,int n,big z)291 void incr(_MIPD_ big x,int n,big z)
292 { /* add int to big number: z=x+n */
293 #ifdef MR_OS_THREADS
294 miracl *mr_mip=get_mip();
295 #endif
296 if (mr_mip->ERNUM) return;
297
298 MR_IN(7)
299
300 convert(_MIPP_ n,mr_mip->w0);
301 mr_select(_MIPP_ x,PLUS,mr_mip->w0,z);
302
303 MR_OUT
304 }
305
decr(_MIPD_ big x,int n,big z)306 void decr(_MIPD_ big x,int n,big z)
307 { /* subtract int from big number: z=x-n */
308 #ifdef MR_OS_THREADS
309 miracl *mr_mip=get_mip();
310 #endif
311 if (mr_mip->ERNUM) return;
312
313 MR_IN(8)
314
315 convert(_MIPP_ n,mr_mip->w0);
316 mr_select(_MIPP_ x,MINUS,mr_mip->w0,z);
317
318 MR_OUT
319 }
320
321