1 /*
2 * (C) 2015,2017 Jack Lloyd
3 * (C) 2017 Ribose Inc
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/ffi.h>
9 #include <botan/internal/ffi_util.h>
10 #include <botan/internal/ffi_rng.h>
11 #include <botan/internal/ffi_mp.h>
12 #include <botan/reducer.h>
13 #include <botan/numthry.h>
14 #include <botan/divide.h>
15 
16 extern "C" {
17 
18 using namespace Botan_FFI;
19 
botan_mp_init(botan_mp_t * mp_out)20 int botan_mp_init(botan_mp_t* mp_out)
21    {
22    return ffi_guard_thunk(__func__, [=]() -> int {
23       if(mp_out == nullptr)
24          return BOTAN_FFI_ERROR_NULL_POINTER;
25 
26       *mp_out = new botan_mp_struct(new Botan::BigInt);
27       return BOTAN_FFI_SUCCESS;
28       });
29    }
30 
botan_mp_clear(botan_mp_t mp)31 int botan_mp_clear(botan_mp_t mp)
32    {
33    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); });
34    }
35 
botan_mp_set_from_int(botan_mp_t mp,int initial_value)36 int botan_mp_set_from_int(botan_mp_t mp, int initial_value)
37    {
38    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
39       if(initial_value >= 0)
40          {
41          bn = Botan::BigInt(static_cast<uint64_t>(initial_value));
42          }
43       else
44          {
45          bn = Botan::BigInt(static_cast<uint64_t>(-initial_value));
46          bn.flip_sign();
47          }
48       });
49    }
50 
botan_mp_set_from_str(botan_mp_t mp,const char * str)51 int botan_mp_set_from_str(botan_mp_t mp, const char* str)
52    {
53    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); });
54    }
55 
botan_mp_set_from_radix_str(botan_mp_t mp,const char * str,size_t radix)56 int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix)
57    {
58    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
59       Botan::BigInt::Base base;
60       if(radix == 10)
61          base = Botan::BigInt::Decimal;
62       else if(radix == 16)
63          base = Botan::BigInt::Hexadecimal;
64       else
65          return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
66 
67       const uint8_t* bytes = Botan::cast_char_ptr_to_uint8(str);
68       const size_t len = strlen(str);
69 
70       bn = Botan::BigInt(bytes, len, base);
71       });
72    }
73 
botan_mp_set_from_mp(botan_mp_t dest,const botan_mp_t source)74 int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source)
75    {
76    return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); });
77    }
78 
botan_mp_is_negative(const botan_mp_t mp)79 int botan_mp_is_negative(const botan_mp_t mp)
80    {
81    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; });
82    }
83 
botan_mp_is_positive(const botan_mp_t mp)84 int botan_mp_is_positive(const botan_mp_t mp)
85    {
86    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; });
87    }
88 
botan_mp_flip_sign(botan_mp_t mp)89 int botan_mp_flip_sign(botan_mp_t mp)
90    {
91    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); });
92    }
93 
botan_mp_from_bin(botan_mp_t mp,const uint8_t bin[],size_t bin_len)94 int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len)
95    {
96    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); });
97    }
98 
botan_mp_to_hex(const botan_mp_t mp,char * out)99 int botan_mp_to_hex(const botan_mp_t mp, char* out)
100    {
101    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
102       const std::string hex = bn.to_hex_string();
103       std::memcpy(out, hex.c_str(), 1 + hex.size());
104       });
105    }
106 
botan_mp_to_str(const botan_mp_t mp,uint8_t digit_base,char * out,size_t * out_len)107 int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len)
108    {
109    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, {
110 
111       if(digit_base == 0 || digit_base == 10)
112          return write_str_output(out, out_len, bn.to_dec_string());
113       else if(digit_base == 16)
114          return write_str_output(out, out_len, bn.to_hex_string());
115       else
116          return BOTAN_FFI_ERROR_BAD_PARAMETER;
117       });
118    }
119 
botan_mp_to_bin(const botan_mp_t mp,uint8_t vec[])120 int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[])
121    {
122    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); });
123    }
124 
botan_mp_to_uint32(const botan_mp_t mp,uint32_t * val)125 int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val)
126    {
127    if(val == nullptr)
128       {
129       return BOTAN_FFI_ERROR_NULL_POINTER;
130       }
131    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); });
132    }
133 
botan_mp_destroy(botan_mp_t mp)134 int botan_mp_destroy(botan_mp_t mp)
135    {
136    return BOTAN_FFI_CHECKED_DELETE(mp);
137    }
138 
botan_mp_add(botan_mp_t result,const botan_mp_t x,const botan_mp_t y)139 int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
140    {
141    return BOTAN_FFI_DO(Botan::BigInt, result, res, {
142       if(result == x)
143          res += safe_get(y);
144       else
145          res = safe_get(x) + safe_get(y);
146       });
147    }
148 
botan_mp_sub(botan_mp_t result,const botan_mp_t x,const botan_mp_t y)149 int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
150    {
151    return BOTAN_FFI_DO(Botan::BigInt, result, res, {
152       if(result == x)
153          res -= safe_get(y);
154       else
155          res = safe_get(x) - safe_get(y);
156       });
157    }
158 
botan_mp_add_u32(botan_mp_t result,const botan_mp_t x,uint32_t y)159 int botan_mp_add_u32(botan_mp_t result, const botan_mp_t x, uint32_t y)
160    {
161    return BOTAN_FFI_DO(Botan::BigInt, result, res, {
162       if(result == x)
163          res += static_cast<Botan::word>(y);
164       else
165          res = safe_get(x) + static_cast<Botan::word>(y);
166       });
167    }
168 
botan_mp_sub_u32(botan_mp_t result,const botan_mp_t x,uint32_t y)169 int botan_mp_sub_u32(botan_mp_t result, const botan_mp_t x, uint32_t y)
170    {
171    return BOTAN_FFI_DO(Botan::BigInt, result, res, {
172       if(result == x)
173          res -= static_cast<Botan::word>(y);
174       else
175          res = safe_get(x) - static_cast<Botan::word>(y);
176       });
177    }
178 
botan_mp_mul(botan_mp_t result,const botan_mp_t x,const botan_mp_t y)179 int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
180    {
181    return BOTAN_FFI_DO(Botan::BigInt, result, res, {
182       if(result == x)
183          res *= safe_get(y);
184       else
185          res = safe_get(x) * safe_get(y);
186       });
187    }
188 
botan_mp_div(botan_mp_t quotient,botan_mp_t remainder,const botan_mp_t x,const botan_mp_t y)189 int botan_mp_div(botan_mp_t quotient,
190                  botan_mp_t remainder,
191                  const botan_mp_t x, const botan_mp_t y)
192    {
193    return BOTAN_FFI_DO(Botan::BigInt, quotient, q, {
194       Botan::BigInt r;
195       Botan::vartime_divide(safe_get(x), safe_get(y), q, r);
196       safe_get(remainder) = r;
197       });
198    }
199 
botan_mp_equal(const botan_mp_t x_w,const botan_mp_t y_w)200 int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w)
201    {
202    return BOTAN_FFI_RETURNING(Botan::BigInt, x_w, x, { return x == safe_get(y_w); });
203    }
204 
botan_mp_is_zero(const botan_mp_t mp)205 int botan_mp_is_zero(const botan_mp_t mp)
206    {
207    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_zero(); });
208    }
209 
botan_mp_is_odd(const botan_mp_t mp)210 int botan_mp_is_odd(const botan_mp_t mp)
211    {
212    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_odd(); });
213    }
214 
botan_mp_is_even(const botan_mp_t mp)215 int botan_mp_is_even(const botan_mp_t mp)
216    {
217    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, bn, { return bn.is_even(); });
218    }
219 
botan_mp_cmp(int * result,const botan_mp_t x_w,const botan_mp_t y_w)220 int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w)
221    {
222    return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); });
223    }
224 
botan_mp_swap(botan_mp_t x_w,botan_mp_t y_w)225 int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w)
226    {
227    return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); });
228    }
229 
230 // Return (base^exponent) % modulus
botan_mp_powmod(botan_mp_t out,const botan_mp_t base,const botan_mp_t exponent,const botan_mp_t modulus)231 int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus)
232    {
233    return BOTAN_FFI_DO(Botan::BigInt, out, o,
234                        { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); });
235    }
236 
botan_mp_lshift(botan_mp_t out,const botan_mp_t in,size_t shift)237 int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift)
238    {
239    return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; });
240    }
241 
botan_mp_rshift(botan_mp_t out,const botan_mp_t in,size_t shift)242 int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift)
243    {
244    return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; });
245    }
246 
botan_mp_mod_inverse(botan_mp_t out,const botan_mp_t in,const botan_mp_t modulus)247 int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus)
248    {
249    return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); });
250    }
251 
botan_mp_mod_mul(botan_mp_t out,const botan_mp_t x,const botan_mp_t y,const botan_mp_t modulus)252 int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus)
253    {
254    return BOTAN_FFI_DO(Botan::BigInt, out, o, {
255       Botan::Modular_Reducer reducer(safe_get(modulus));
256       o = reducer.multiply(safe_get(x), safe_get(y));
257       });
258    }
259 
botan_mp_rand_bits(botan_mp_t rand_out,botan_rng_t rng,size_t bits)260 int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits)
261    {
262    return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
263       safe_get(rand_out).randomize(r, bits); });
264    }
265 
botan_mp_rand_range(botan_mp_t rand_out,botan_rng_t rng,const botan_mp_t lower,const botan_mp_t upper)266 int botan_mp_rand_range(botan_mp_t rand_out,
267                         botan_rng_t rng,
268                         const botan_mp_t lower,
269                         const botan_mp_t upper)
270    {
271    return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
272       safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); });
273    }
274 
botan_mp_gcd(botan_mp_t out,const botan_mp_t x,const botan_mp_t y)275 int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y)
276    {
277    return BOTAN_FFI_DO(Botan::BigInt, out, o, {
278       o = Botan::gcd(safe_get(x), safe_get(y)); });
279    }
280 
botan_mp_is_prime(const botan_mp_t mp,botan_rng_t rng,size_t test_prob)281 int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob)
282    {
283    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n,
284                        { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; });
285    }
286 
botan_mp_get_bit(const botan_mp_t mp,size_t bit)287 int botan_mp_get_bit(const botan_mp_t mp, size_t bit)
288    {
289    return BOTAN_FFI_RETURNING(Botan::BigInt, mp, n, { return (n.get_bit(bit)); });
290    }
291 
botan_mp_set_bit(botan_mp_t mp,size_t bit)292 int botan_mp_set_bit(botan_mp_t mp, size_t bit)
293    {
294    return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); });
295    }
296 
botan_mp_clear_bit(botan_mp_t mp,size_t bit)297 int botan_mp_clear_bit(botan_mp_t mp, size_t bit)
298    {
299    return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); });
300    }
301 
botan_mp_num_bits(const botan_mp_t mp,size_t * bits)302 int botan_mp_num_bits(const botan_mp_t mp, size_t* bits)
303    {
304    return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); });
305    }
306 
botan_mp_num_bytes(const botan_mp_t mp,size_t * bytes)307 int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes)
308    {
309    return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); });
310    }
311 
312 }
313