1 /**
2 * Botan BigInt operations
3 * 
4 * Copyright:
5 * (C) 1999-2010,2014 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *      2006 Luca Piccarreta
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan_math.mp_bigint;
13 
14 import botan_math.mp_word;
15 
16 /*
17 * The size of the word type, in bits
18 */
19 const size_t MP_WORD_BITS = BOTAN_MP_WORD_BITS;
20 
21 /**
22 * Two operand addition
23 * Params:
24 *  x = the first operand (and output)
25 *  x_size = size of x
26 *  y = the second operand
27 *  y_size = size of y (must be >= x_size)
28 */
29 void bigint_add2(word* x, size_t x_size, in word* y, size_t y_size)
30 {
31 	if (bigint_add2_nc(x, x_size, y, y_size))
32 		x[x_size] += 1;
33 }
34 
35 /**
36 * Three operand addition
37 */
38 void bigint_add3(word* z, in word* x, size_t x_size,
39 	in word* y, size_t y_size)
40 {
41 	z[(x_size > y_size ? x_size : y_size)] += bigint_add3_nc(z, x, x_size, y, y_size);
42 }
43 
44 /**
45 * Two operand addition with carry out
46 */
47 word bigint_add2_nc(word* x, size_t x_size, in word* y, size_t y_size)
48 {
49 	word carry = 0;
50 	
51 	assert(x_size >= y_size, "Expected sizes");
52 	
53 	const size_t blocks = y_size - (y_size % 8);
54 	
55 	for (size_t i = 0; i != blocks; i += 8)
56 		carry = word8_add2((x + i)[0 .. 8], (y + i)[0 .. 8], carry);
57 	
58 	foreach (size_t i; blocks .. y_size)
59 		x[i] = word_add(x[i], y[i], &carry);
60 	
61 	foreach (size_t i; y_size .. x_size)
62 		x[i] = word_add(x[i], 0, &carry);
63 	
64 	return carry;
65 }
66 
67 /**
68 * Three operand addition with carry out
69 */
70 word bigint_add3_nc(word* z, in word* x, size_t x_size, in word* y, size_t y_size)
71 {
72 	if (x_size < y_size)
73 	{ return bigint_add3_nc(z, y, y_size, x, x_size); }
74 	
75 	word carry = 0;
76 	
77 	const size_t blocks = y_size - (y_size % 8);
78 	
79 	for (size_t i = 0; i != blocks; i += 8)
80 		carry = word8_add3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), *cast(word[8]*) (y + i), carry);
81 	
82 	foreach (size_t i; blocks .. y_size)
83 		z[i] = word_add(x[i], y[i], &carry);
84 	
85 	foreach (size_t i; y_size .. x_size)
86 		z[i] = word_add(x[i], 0, &carry);
87 	
88 	return carry;
89 }
90 
91 /**
92 * Two operand subtraction
93 */
94 word bigint_sub2(word* x, size_t x_size, in word* y, size_t y_size)
95 {
96 	word borrow = 0;
97 	
98 	assert(x_size >= y_size, "Expected sizes");
99 	
100 	const size_t blocks = y_size - (y_size % 8);
101 	
102 	for (size_t i = 0; i != blocks; i += 8)
103 		borrow = word8_sub2(*cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow);
104 	
105 	foreach (size_t i; blocks .. y_size)
106 		x[i] = word_sub(x[i], y[i], &borrow);
107 	
108 	foreach (size_t i; y_size .. x_size)
109 		x[i] = word_sub(x[i], 0, &borrow);
110 	
111 	return borrow;
112 }
113 
114 /**
115 * Two operand subtraction, x = y - x; assumes y >= x
116 */
117 void bigint_sub2_rev(word* x,  in word* y, size_t y_size)
118 {
119 	word borrow = 0;
120 	
121 	const size_t blocks = y_size - (y_size % 8);
122 	
123 	for (size_t i = 0; i != blocks; i += 8)
124 		borrow = word8_sub2_rev(*cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow);
125 	
126 	foreach (size_t i; blocks .. y_size)
127 		x[i] = word_sub(y[i], x[i], &borrow);
128 	
129 	assert(!borrow, "y must be greater than x");
130 }
131 
132 /**
133 * Three operand subtraction
134 */
135 word bigint_sub3(word* z, in word* x, size_t x_size, in word* y, size_t y_size)
136 {
137 	word borrow = 0;
138 	
139 	assert(x_size >= y_size, "Expected sizes");
140 	
141 	const size_t blocks = y_size - (y_size % 8);
142 	
143 	for (size_t i = 0; i != blocks; i += 8)
144 		borrow = word8_sub3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), *cast(word[8]*) (y + i), borrow);
145 	
146 	foreach (size_t i; blocks .. y_size)
147 		z[i] = word_sub(x[i], y[i], &borrow);
148 	
149 	foreach (size_t i; y_size .. x_size)
150 		z[i] = word_sub(x[i], 0, &borrow);
151 	
152 	return borrow;
153 }
154 
155 /*
156 * Shift Operations
157 */
158 
159 /*
160 * Single Operand Left Shift
161 */
162 void bigint_shl1(word* x, size_t x_size, size_t word_shift, size_t bit_shift)
163 {
164 	if (word_shift)
165 	{
166 		copyMem(x + word_shift, x, x_size);
167 		clearMem(x, word_shift);
168 	}
169 	
170 	if (bit_shift)
171 	{
172 		word carry = 0;
173 		foreach (size_t j; word_shift .. (x_size + word_shift + 1))
174 		{
175 			word temp = x[j];
176 			x[j] = (temp << bit_shift) | carry;
177 			carry = (temp >> (MP_WORD_BITS - bit_shift));
178 		}
179 	}
180 }
181 
182 /*
183 * Single Operand Right Shift
184 */
185 void bigint_shr1(word* x, size_t x_size, size_t word_shift, size_t bit_shift)
186 {
187 	if (x_size < word_shift)
188 	{
189 		clearMem(x, x_size);
190 		return;
191 	}
192 	
193 	if (word_shift)
194 	{
195 		copyMem(x, x + word_shift, x_size - word_shift);
196 		clearMem(x + x_size - word_shift, word_shift);
197 	}
198 	
199 	if (bit_shift)
200 	{
201 		word carry = 0;
202 		
203 		size_t top = x_size - word_shift;
204 		
205 		while (top >= 4)
206 		{
207 			word w = x[top-1];
208 			x[top-1] = (w >> bit_shift) | carry;
209 			carry = (w << (MP_WORD_BITS - bit_shift));
210 			
211 			w = x[top-2];
212 			x[top-2] = (w >> bit_shift) | carry;
213 			carry = (w << (MP_WORD_BITS - bit_shift));
214 			
215 			w = x[top-3];
216 			x[top-3] = (w >> bit_shift) | carry;
217 			carry = (w << (MP_WORD_BITS - bit_shift));
218 			
219 			w = x[top-4];
220 			x[top-4] = (w >> bit_shift) | carry;
221 			carry = (w << (MP_WORD_BITS - bit_shift));
222 			
223 			top -= 4;
224 		}
225 		
226 		while (top)
227 		{
228 			word w = x[top-1];
229 			x[top-1] = (w >> bit_shift) | carry;
230 			carry = (w << (MP_WORD_BITS - bit_shift));
231 			
232 			top--;
233 		}
234 	}
235 }
236 
237 /*
238 * Two Operand Left Shift
239 */
240 void bigint_shl2(word* y, in word* x, size_t x_size, size_t word_shift, size_t bit_shift)
241 {
242 	foreach (size_t j; 0 .. x_size)
243 		y[j + word_shift] = x[j];
244 	if (bit_shift)
245 	{
246 		word carry = 0;
247 		foreach (size_t j; word_shift .. (x_size + word_shift + 1))
248 		{
249 			word w = y[j];
250 			y[j] = (w << bit_shift) | carry;
251 			carry = (w >> (MP_WORD_BITS - bit_shift));
252 		}
253 	}
254 }
255 
256 /*
257 * Two Operand Right Shift
258 */
259 void bigint_shr2(word* y, in word* x, size_t x_size,
260 	size_t word_shift, size_t bit_shift)
261 {
262 	if (x_size < word_shift) return;
263 	
264 	foreach (size_t j; 0 .. (x_size - word_shift))
265 		y[j] = x[j + word_shift];
266 	if (bit_shift)
267 	{
268 		word carry = 0;
269 		for (size_t j = x_size - word_shift; j > 0; --j)
270 		{
271 			word w = y[j-1];
272 			y[j-1] = (w >> bit_shift) | carry;
273 			carry = (w << (MP_WORD_BITS - bit_shift));
274 		}
275 	}
276 }
277 
278 /*
279 * Simple O(N^2) Multiplication and Squaring
280 */
281 void bigint_simple_mul(word* z, in word* x, size_t x_size, in word* y, size_t y_size)
282 {
283 	const size_t x_size_8 = x_size - (x_size % 8);
284 	
285 	clearMem(z, x_size + y_size);
286 	
287 	foreach (size_t i; 0 .. y_size)
288 	{
289 		const word y_i = y[i];
290 		
291 		word carry = 0;
292 		
293 		for (size_t j = 0; j != x_size_8; j += 8)
294 			carry = word8_madd3(*cast(word[8]*) (z + i + j), *cast(word[8]*) (x + j), y_i, carry);
295 		
296 		foreach (size_t j; x_size_8 .. x_size)
297 			z[i+j] = word_madd3(x[j], y_i, z[i+j], &carry);
298 		
299 		z[x_size+i] = carry;
300 	}
301 }
302 
303 /*
304 * Simple O(N^2) Squaring
305 *
306 * This is exactly the same algorithm as bigint_simple_mul, however
307 * because C/C++ compilers suck at alias analysis it is good to have
308 * the version where the compiler knows that x == y
309 *
310 * There is an O(n^1.5) squaring algorithm specified in Handbook of
311 * Applied Cryptography, chapter 14
312 *
313 */
314 void bigint_simple_sqr(word* z, in word* x, size_t x_size)
315 {
316 	const size_t x_size_8 = x_size - (x_size % 8);
317 	
318 	clearMem(z, 2*x_size);
319 	
320 	foreach (size_t i; 0 .. x_size)
321 	{
322 		const word x_i = x[i];
323 		word carry = 0;
324 		
325 		for (size_t j = 0; j != x_size_8; j += 8)
326 			carry = word8_madd3(*cast(word[8]*) (z + i + j), *cast(word[8]*) (x + j), x_i, carry);
327 		
328 		foreach (size_t j; x_size_8 .. x_size)
329 			z[i+j] = word_madd3(x[j], x_i, z[i+j], &carry);
330 		
331 		z[x_size+i] = carry;
332 	}
333 }
334 
335 
336 /*
337 * Linear Multiply
338 */
339 /*
340 * Two Operand Linear Multiply
341 */
342 void bigint_linmul2(word* x, size_t x_size, word y)
343 {
344 	const size_t blocks = x_size - (x_size % 8);
345 	
346 	word carry = 0;
347 	
348 	for (size_t i = 0; i != blocks; i += 8)
349 		carry = word8_linmul2(*cast(word[8]*) (x + i), y, carry);
350 	
351 	foreach (size_t i; blocks .. x_size) {
352 		x[i] = word_madd2(x[i], y, &carry);
353 	}
354 	x[x_size] = carry;
355 }
356 
357 /*
358 * Three Operand Linear Multiply
359 */
360 void bigint_linmul3(word* z, in word* x, size_t x_size, word y)
361 {
362 	const size_t blocks = x_size - (x_size % 8);
363 	
364 	word carry = 0;
365 	
366 	for (size_t i = 0; i != blocks; i += 8)
367 		carry = word8_linmul3(*cast(word[8]*) (z + i), *cast(word[8]*) (x + i), y, carry);
368 	
369 	foreach (size_t i; blocks .. x_size)
370 		z[i] = word_madd2(x[i], y, &carry);
371 	
372 	z[x_size] = carry;
373 }
374 
375 
376 
377 /**
378 * Compare x and y
379 */
380 int bigint_cmp(in word* x, size_t x_size,
381 	in word* y, size_t y_size)
382 {
383 	if (x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); }
384 	
385 	while (x_size > y_size)
386 	{
387 		if (x[x_size-1])
388 			return 1;
389 		x_size--;
390 	}
391 	
392 	for (size_t i = x_size; i > 0; --i)
393 	{
394 		if (x[i-1] > y[i-1])
395 			return 1;
396 		if (x[i-1] < y[i-1])
397 			return -1;
398 	}
399 	
400 	return 0;
401 }
402 
403 /**
404 * Compute ((n1<<bits) + n0) / d
405 */
406 word bigint_divop(word n1, word n0, word d)
407 {
408 	word high = n1 % d, quotient = 0;
409 	
410 	foreach (size_t i; 0 .. MP_WORD_BITS)
411 	{
412 		word high_top_bit = (high & MP_WORD_TOP_BIT);
413 		
414 		high <<= 1;
415 		high |= (n0 >> (MP_WORD_BITS-1-i)) & 1;
416 		quotient <<= 1;
417 		
418 		if (high_top_bit || high >= d)
419 		{
420 			high -= d;
421 			quotient |= 1;
422 		}
423 	}
424 	
425 	return quotient;
426 }
427 
428 /**
429 * Compute ((n1<<bits) + n0) % d
430 */
431 word bigint_modop(word n1, word n0, word d)
432 {
433 	word z = bigint_divop(n1, n0, d);
434 	word dummy = 0;
435 	z = word_madd2(z, d, &dummy);
436 	return (n0-z);
437 }