1 /**
2 * Karatsuba 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_karatsuba;
13 
14 import botan_math.mp_types;
15 import botan_math.mp_bigint;
16 import botan_math.mp_comba;
17 
18 __gshared immutable size_t KARATSUBA_MULTIPLY_THRESHOLD = 32;
19 __gshared immutable size_t KARATSUBA_SQUARE_THRESHOLD = 32;
20 
21 /*
22 * Karatsuba Multiplication Operation
23 */
24 void karatsuba_mul(word* z, in word* x, in word* y, size_t N, word* workspace)
25 {
26 	if (N < KARATSUBA_MULTIPLY_THRESHOLD || N % 2)
27 	{
28 		if (N == 6)
29 			return bigint_comba_mul6(*cast(word[12]*) z, *cast(word[6]*) x, *cast(word[6]*) y);
30 		else if (N == 8)
31 			return bigint_comba_mul8(*cast(word[16]*) z, *cast(word[8]*) x, *cast(word[8]*) y);
32 		else if (N == 16)
33 			return bigint_comba_mul16(*cast(word[32]*) z, *cast(word[16]*) x, *cast(word[16]*) y);
34 		else
35 			return bigint_simple_mul(z, x, N, y, N);
36 	}
37 	
38 	const size_t N2 = N / 2;
39 	
40 	const word* x0 = x;
41 	const word* x1 = x + N2;
42 	const word* y0 = y;
43 	const word* y1 = y + N2;
44 	word* z0 = z;
45 	word* z1 = z + N;
46 	
47 	const int cmp0 = bigint_cmp(x0, N2, x1, N2);
48 	const int cmp1 = bigint_cmp(y1, N2, y0, N2);
49 	
50 	clearMem(workspace, 2*N);
51 	
52 	//if (cmp0 && cmp1)
53 	{
54 		if (cmp0 > 0)
55 			bigint_sub3(z0, x0, N2, x1, N2);
56 		else
57 			bigint_sub3(z0, x1, N2, x0, N2);
58 		
59 		if (cmp1 > 0)
60 			bigint_sub3(z1, y1, N2, y0, N2);
61 		else
62 			bigint_sub3(z1, y0, N2, y1, N2);
63 		
64 		karatsuba_mul(workspace, z0, z1, N2, workspace+N);
65 	}
66 	
67 	karatsuba_mul(z0, x0, y0, N2, workspace+N);
68 	karatsuba_mul(z1, x1, y1, N2, workspace+N);
69 	
70 	const word ws_carry = bigint_add3_nc(workspace + N, z0, N, z1, N);
71 	word z_carry = bigint_add2_nc(z + N2, N, workspace + N, N);
72 	
73 	z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1);
74 	bigint_add2_nc(z + N + N2, N2, &z_carry, 1);
75 	
76 	if ((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0))
77 		bigint_add2(z + N2, 2*N-N2, workspace, N);
78 	else
79 		bigint_sub2(z + N2, 2*N-N2, workspace, N);
80 }
81 
82 /*
83 * Karatsuba Squaring Operation
84 */
85 void karatsuba_sqr(word* z, in word* x, size_t N, word* workspace)
86 {
87 	if (N < KARATSUBA_SQUARE_THRESHOLD || N % 2)
88 	{
89 		if (N == 6)
90 			return bigint_comba_sqr6(*cast(word[12]*) z, *cast(word[6]*) x);
91 		else if (N == 8)
92 			return bigint_comba_sqr8(*cast(word[16]*) z, *cast(word[8]*) x);
93 		else if (N == 16)
94 			return bigint_comba_sqr16(*cast(word[32]*) z, *cast(word[16]*) x);
95 		else
96 			return bigint_simple_sqr(z, x, N);
97 	}
98 	
99 	const size_t N2 = N / 2;
100 	
101 	const word* x0 = x;
102 	const word* x1 = x + N2;
103 	word* z0 = z;
104 	word* z1 = z + N;
105 	
106 	const int cmp = bigint_cmp(x0, N2, x1, N2);
107 	
108 	clearMem(workspace, 2*N);
109 	
110 	//if (cmp)
111 	{
112 		if (cmp > 0)
113 			bigint_sub3(z0, x0, N2, x1, N2);
114 		else
115 			bigint_sub3(z0, x1, N2, x0, N2);
116 		
117 		karatsuba_sqr(workspace, z0, N2, workspace+N);
118 	}
119 	
120 	karatsuba_sqr(z0, x0, N2, workspace+N);
121 	karatsuba_sqr(z1, x1, N2, workspace+N);
122 	
123 	const word ws_carry = bigint_add3_nc(workspace + N, z0, N, z1, N);
124 	word z_carry = bigint_add2_nc(z + N2, N, workspace + N, N);
125 	
126 	z_carry += bigint_add2_nc(z + N + N2, N2, &ws_carry, 1);
127 	bigint_add2_nc(z + N + N2, N2, &z_carry, 1);
128 	
129 	/*
130     * This is only actually required if cmp is != 0, however
131     * if cmp==0 then workspace[0:N] == 0 and avoiding the jump
132     * hides a timing channel.
133     */
134 	bigint_sub2(z + N2, 2*N-N2, workspace, N);
135 }
136 
137 /*
138 * Pick a good size for the Karatsuba multiply
139 */
140 size_t karatsuba_size(size_t z_size,
141 	size_t x_size, size_t x_sw,
142 	size_t y_size, size_t y_sw)
143 {
144 	if (x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size)
145 		return 0;
146 	
147 	if (((x_size == x_sw) && (x_size % 2)) ||
148 		((y_size == y_sw) && (y_size % 2)))
149 		return 0;
150 	
151 	const size_t start = (x_sw > y_sw) ? x_sw : y_sw;
152 	const size_t end = (x_size < y_size) ? x_size : y_size;
153 	
154 	if (start == end)
155 	{
156 		if (start % 2)
157 			return 0;
158 		return start;
159 	}
160 	
161 	for (size_t j = start; j <= end; ++j)
162 	{
163 		if (j % 2)
164 			continue;
165 		
166 		if (2*j > z_size)
167 			return 0;
168 		
169 		if (x_sw <= j && j <= x_size && y_sw <= j && j <= y_size)
170 		{
171 			if (j % 4 == 2 &&
172 				(j+2) <= x_size && (j+2) <= y_size && 2*(j+2) <= z_size)
173 				return j+2;
174 			return j;
175 		}
176 	}
177 	
178 	return 0;
179 }
180 
181 /*
182 * Pick a good size for the Karatsuba squaring
183 */
184 size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw)
185 {
186 	if (x_sw == x_size)
187 	{
188 		if (x_sw % 2)
189 			return 0;
190 		return x_sw;
191 	}
192 	
193 	for (size_t j = x_sw; j <= x_size; ++j)
194 	{
195 		if (j % 2)
196 			continue;
197 		
198 		if (2*j > z_size)
199 			return 0;
200 		
201 		if (j % 4 == 2 && (j+2) <= x_size && 2*(j+2) <= z_size)
202 			return j+2;
203 		return j;
204 	}
205 	
206 	return 0;
207 }