Botan 3.3.0
Crypto and TLS for C&
divide.cpp
Go to the documentation of this file.
1/*
2* Division Algorithms
3* (C) 1999-2007,2012,2018,2021 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/internal/divide.h>
9
10#include <botan/internal/bit_ops.h>
11#include <botan/internal/ct_utils.h>
12#include <botan/internal/mp_core.h>
13
14namespace Botan {
15
16namespace {
17
18/*
19* Handle signed operands, if necessary
20*/
21void sign_fixup(const BigInt& x, const BigInt& y, BigInt& q, BigInt& r) {
22 q.cond_flip_sign(x.sign() != y.sign());
23
24 if(x.is_negative() && r.is_nonzero()) {
25 q -= 1;
26 r = y.abs() - r;
27 }
28}
29
30inline bool division_check(word q, word y2, word y1, word x3, word x2, word x1) {
31 /*
32 Compute (y3,y2,y1) = (y2,y1) * q
33 and return true if (y3,y2,y1) > (x3,x2,x1)
34 */
35
36 word y3 = 0;
37 y1 = word_madd2(q, y1, &y3);
38 y2 = word_madd2(q, y2, &y3);
39
40 const word x[3] = {x1, x2, x3};
41 const word y[3] = {y1, y2, y3};
42
43 return bigint_ct_is_lt(x, 3, y, 3).as_bool();
44}
45
46} // namespace
47
48void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out) {
49 if(y.is_zero()) {
50 throw Invalid_Argument("ct_divide: cannot divide by zero");
51 }
52
53 const size_t x_words = x.sig_words();
54 const size_t y_words = y.sig_words();
55
56 const size_t x_bits = x.bits();
57
58 BigInt q = BigInt::with_capacity(x_words);
59 BigInt r = BigInt::with_capacity(y_words);
60 BigInt t = BigInt::with_capacity(y_words); // a temporary
61
62 for(size_t i = 0; i != x_bits; ++i) {
63 const size_t b = x_bits - 1 - i;
64 const bool x_b = x.get_bit(b);
65
66 r *= 2;
67 r.conditionally_set_bit(0, x_b);
68
69 const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0;
70
71 q.conditionally_set_bit(b, r_gte_y);
72 r.ct_cond_swap(r_gte_y, t);
73 }
74
75 sign_fixup(x, y, q, r);
76 r_out = r;
77 q_out = q;
78}
79
80void ct_divide_word(const BigInt& x, word y, BigInt& q_out, word& r_out) {
81 if(y == 0) {
82 throw Invalid_Argument("ct_divide_word: cannot divide by zero");
83 }
84
85 const size_t x_words = x.sig_words();
86 const size_t x_bits = x.bits();
87
88 BigInt q = BigInt::with_capacity(x_words);
89 word r = 0;
90
91 for(size_t i = 0; i != x_bits; ++i) {
92 const size_t b = x_bits - 1 - i;
93 const bool x_b = x.get_bit(b);
94
95 const auto r_carry = CT::Mask<word>::expand(r >> (BOTAN_MP_WORD_BITS - 1));
96
97 r *= 2;
98 r += x_b;
99
100 const auto r_gte_y = CT::Mask<word>::is_gte(r, y) | r_carry;
101 q.conditionally_set_bit(b, r_gte_y.as_bool());
102 r = r_gte_y.select(r - y, r);
103 }
104
105 if(x.is_negative()) {
106 q.flip_sign();
107 if(r != 0) {
108 --q;
109 r = y - r;
110 }
111 }
112
113 r_out = r;
114 q_out = q;
115}
116
117BigInt ct_modulo(const BigInt& x, const BigInt& y) {
118 if(y.is_negative() || y.is_zero()) {
119 throw Invalid_Argument("ct_modulo requires y > 0");
120 }
121
122 const size_t y_words = y.sig_words();
123
124 const size_t x_bits = x.bits();
125
126 BigInt r = BigInt::with_capacity(y_words);
127 BigInt t = BigInt::with_capacity(y_words);
128
129 for(size_t i = 0; i != x_bits; ++i) {
130 const size_t b = x_bits - 1 - i;
131 const bool x_b = x.get_bit(b);
132
133 r *= 2;
134 r.conditionally_set_bit(0, x_b);
135
136 const bool r_gte_y = bigint_sub3(t.mutable_data(), r.data(), r.size(), y.data(), y_words) == 0;
137
138 r.ct_cond_swap(r_gte_y, t);
139 }
140
141 if(x.is_negative()) {
142 if(r.is_nonzero()) {
143 r = y - r;
144 }
145 }
146
147 return r;
148}
149
150/*
151* Solve x = q * y + r
152*
153* See Handbook of Applied Cryptography section 14.2.5
154*/
155void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt& r_out) {
156 if(y_arg.is_zero()) {
157 throw Invalid_Argument("vartime_divide: cannot divide by zero");
158 }
159
160 const size_t y_words = y_arg.sig_words();
161
162 BOTAN_ASSERT_NOMSG(y_words > 0);
163
164 BigInt y = y_arg;
165
166 BigInt r = x;
167 BigInt q = BigInt::zero();
169
172
173 // Calculate shifts needed to normalize y with high bit set
174 const size_t shifts = y.top_bits_free();
175
176 y <<= shifts;
177 r <<= shifts;
178
179 // we know y has not changed size, since we only shifted up to set high bit
180 const size_t t = y_words - 1;
181 const size_t n = std::max(y_words, r.sig_words()) - 1; // r may have changed size however
182
183 BOTAN_ASSERT_NOMSG(n >= t);
184
185 q.grow_to(n - t + 1);
186
187 word* q_words = q.mutable_data();
188
189 BigInt shifted_y = y << (BOTAN_MP_WORD_BITS * (n - t));
190
191 // Set q_{n-t} to number of times r > shifted_y
192 q_words[n - t] = r.reduce_below(shifted_y, ws);
193
194 const word y_t0 = y.word_at(t);
195 const word y_t1 = y.word_at(t - 1);
196 BOTAN_DEBUG_ASSERT((y_t0 >> (BOTAN_MP_WORD_BITS - 1)) == 1);
197
198 for(size_t j = n; j != t; --j) {
199 const word x_j0 = r.word_at(j);
200 const word x_j1 = r.word_at(j - 1);
201 const word x_j2 = r.word_at(j - 2);
202
203 word qjt = bigint_divop_vartime(x_j0, x_j1, y_t0);
204
205 qjt = CT::Mask<word>::is_equal(x_j0, y_t0).select(MP_WORD_MAX, qjt);
206
207 // Per HAC 14.23, this operation is required at most twice
208 qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2);
209 qjt -= division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2);
210 BOTAN_DEBUG_ASSERT(division_check(qjt, y_t0, y_t1, x_j0, x_j1, x_j2) == false);
211
212 shifted_y >>= BOTAN_MP_WORD_BITS;
213 // Now shifted_y == y << (BOTAN_MP_WORD_BITS * (j-t-1))
214
215 // TODO this sequence could be better
216 r -= qjt * shifted_y;
217 qjt -= r.is_negative();
218 r += static_cast<word>(r.is_negative()) * shifted_y;
219
220 q_words[j - t - 1] = qjt;
221 }
222
223 r >>= shifts;
224
225 sign_fixup(x, y_arg, q, r);
226
227 r_out = r;
228 q_out = q;
229}
230
231} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98
static BigInt zero()
Definition bigint.h:45
size_t sig_words() const
Definition bigint.h:584
void conditionally_set_bit(size_t n, bool set_it)
Definition bigint.h:444
word * mutable_data()
Definition bigint.h:609
size_t size() const
Definition bigint.h:578
void grow_to(size_t n) const
Definition bigint.h:631
void flip_sign()
Definition bigint.h:555
size_t top_bits_free() const
Definition bigint.cpp:281
const word * data() const
Definition bigint.h:615
word word_at(size_t n) const
Definition bigint.h:518
size_t bits() const
Definition bigint.cpp:290
void ct_cond_swap(bool predicate, BigInt &other)
Definition bigint.cpp:467
bool is_zero() const
Definition bigint.h:428
size_t reduce_below(const BigInt &mod, secure_vector< word > &ws)
Definition bigint.cpp:312
bool is_negative() const
Definition bigint.h:528
bool is_nonzero() const
Definition bigint.h:422
bool get_bit(size_t n) const
Definition bigint.h:467
static BigInt with_capacity(size_t n)
Definition bigint.cpp:58
void set_sign(Sign sign)
Definition bigint.h:561
static Mask< T > is_equal(T x, T y)
Definition ct_utils.h:128
static Mask< T > expand(T v)
Definition ct_utils.h:109
static Mask< T > is_gte(T x, T y)
Definition ct_utils.h:148
#define BOTAN_MP_WORD_BITS
Definition build.h:50
void vartime_divide(const BigInt &x, const BigInt &y_arg, BigInt &q_out, BigInt &r_out)
Definition divide.cpp:155
const word MP_WORD_MAX
Definition mp_core.h:22
BigInt ct_modulo(const BigInt &x, const BigInt &y)
Definition divide.cpp:117
CT::Mask< word > bigint_ct_is_lt(const word x[], size_t x_size, const word y[], size_t y_size, bool lt_or_equal=false)
Definition mp_core.h:536
word bigint_divop_vartime(word n1, word n0, word d)
Definition mp_core.h:665
void ct_divide(const BigInt &x, const BigInt &y, BigInt &q_out, BigInt &r_out)
Definition divide.cpp:48
void ct_divide_word(const BigInt &x, word y, BigInt &q_out, word &r_out)
Definition divide.cpp:80
word word_madd2(word a, word b, word *c)
Definition mp_asmi.h:44
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
word bigint_sub3(word z[], const word x[], size_t x_size, const word y[], size_t y_size)
Definition mp_core.h:321