aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/ffi/ffi_mp.cpp
blob: 00ad786abcb96ce25c58c61ce5a878a635e83c46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
* (C) 2015,2017 Jack Lloyd
* (C) 2017 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ffi.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_rng.h>
#include <botan/internal/ffi_mp.h>
#include <botan/reducer.h>
#include <botan/numthry.h>
#include <botan/divide.h>

extern "C" {

using namespace Botan_FFI;

int botan_mp_init(botan_mp_t* mp_out)
   {
   return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
      BOTAN_ASSERT_ARG_NON_NULL(mp_out);

      *mp_out = new botan_mp_struct(new Botan::BigInt);
      return BOTAN_FFI_SUCCESS;
      });
   }

int botan_mp_clear(botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.clear(); });
   }

int botan_mp_set_from_int(botan_mp_t mp, int initial_value)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
      if(initial_value >= 0)
         {
         bn = Botan::BigInt(static_cast<uint64_t>(initial_value));
         }
      else
         {
         bn = Botan::BigInt(static_cast<uint64_t>(-initial_value));
         bn.flip_sign();
         }
      });
   }

int botan_mp_set_from_str(botan_mp_t mp, const char* str)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn = Botan::BigInt(str); });
   }

int botan_mp_set_from_radix_str(botan_mp_t mp, const char* str, size_t radix)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
      Botan::BigInt::Base base;
      if(radix == 10)
         base = Botan::BigInt::Decimal;
      else if(radix == 16)
         base = Botan::BigInt::Hexadecimal;
      else
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;

      const uint8_t* bytes = reinterpret_cast<const uint8_t*>(str);
      const size_t len = strlen(str);

      bn = Botan::BigInt::decode(bytes, len, base);
      });
   }

int botan_mp_set_from_mp(botan_mp_t dest, const botan_mp_t source)
   {
   return BOTAN_FFI_DO(Botan::BigInt, dest, bn, { bn = safe_get(source); });
   }

int botan_mp_is_negative(const botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_negative() ? 1 : 0; });
   }

int botan_mp_is_positive(const botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_positive() ? 1 : 0; });
   }

int botan_mp_flip_sign(botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.flip_sign(); });
   }

int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_decode(bin, bin_len); });
   }

int botan_mp_to_hex(const botan_mp_t mp, char* out)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
      std::vector<uint8_t> hex = Botan::BigInt::encode(bn, Botan::BigInt::Hexadecimal);
      std::memcpy(out, hex.data(), hex.size());
      out[hex.size()] = 0; // null terminate
      });
   }

int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t* out_len)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
      Botan::BigInt::Base base;
      if(digit_base == 0 || digit_base == 10)
         base = Botan::BigInt::Decimal;
      else if(digit_base == 16)
         base = Botan::BigInt::Hexadecimal;
      else
         throw FFI_Error("botan_mp_to_str invalid digit base");

      std::vector<uint8_t> hex = Botan::BigInt::encode(bn, base);
      hex.push_back(0); // null terminator
      return write_str_output(out, out_len, hex);
      });
   }

int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[])
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { bn.binary_encode(vec); });
   }

int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val)
   {
   if(val == nullptr) {
   return BOTAN_FFI_ERROR_NULL_POINTER;
   }
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { *val = bn.to_u32bit(); });
   }

int botan_mp_destroy(botan_mp_t mp)
   {
   return BOTAN_FFI_CHECKED_DELETE(mp);
   }

int botan_mp_add(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
   {
   return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) + safe_get(y); });
   }

int botan_mp_sub(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
   {
   return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) - safe_get(y); });
   }

int botan_mp_mul(botan_mp_t result, const botan_mp_t x, const botan_mp_t y)
   {
   return BOTAN_FFI_DO(Botan::BigInt, result, res, { res = safe_get(x) * safe_get(y); });
   }

int botan_mp_div(botan_mp_t quotient,
                 botan_mp_t remainder,
                 const botan_mp_t x, const botan_mp_t y)
   {
   return BOTAN_FFI_DO(Botan::BigInt, quotient, q, {
      Botan::BigInt r;
      Botan::divide(safe_get(x), safe_get(y), q, r);
      safe_get(remainder) = r;
      });
   }

int botan_mp_equal(const botan_mp_t x_w, const botan_mp_t y_w)
   {
   return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { return x == safe_get(y_w); });
   }

int botan_mp_is_zero(const botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_zero(); });
   }

int botan_mp_is_odd(const botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_odd(); });
   }

int botan_mp_is_even(const botan_mp_t mp)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, bn, { return bn.is_even(); });
   }

int botan_mp_cmp(int* result, const botan_mp_t x_w, const botan_mp_t y_w)
   {
   return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { *result = x.cmp(safe_get(y_w)); });
   }

int botan_mp_swap(botan_mp_t x_w, botan_mp_t y_w)
   {
   return BOTAN_FFI_DO(Botan::BigInt, x_w, x, { x.swap(safe_get(y_w)); });
   }

// Return (base^exponent) % modulus
int botan_mp_powmod(botan_mp_t out, const botan_mp_t base, const botan_mp_t exponent, const botan_mp_t modulus)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o,
                       { o = Botan::power_mod(safe_get(base), safe_get(exponent), safe_get(modulus)); });
   }

int botan_mp_lshift(botan_mp_t out, const botan_mp_t in, size_t shift)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) << shift; });
   }

int botan_mp_rshift(botan_mp_t out, const botan_mp_t in, size_t shift)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = safe_get(in) >> shift; });
   }

int botan_mp_mod_inverse(botan_mp_t out, const botan_mp_t in, const botan_mp_t modulus)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o, { o = Botan::inverse_mod(safe_get(in), safe_get(modulus)); });
   }

int botan_mp_mod_mul(botan_mp_t out, const botan_mp_t x, const botan_mp_t y, const botan_mp_t modulus)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o, {
      Botan::Modular_Reducer reducer(safe_get(modulus));
      o = reducer.multiply(safe_get(x), safe_get(y));
      });
   }

int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits)
   {
   return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
      safe_get(rand_out).randomize(r, bits); });
   }

int botan_mp_rand_range(botan_mp_t rand_out,
                        botan_rng_t rng,
                        const botan_mp_t lower,
                        const botan_mp_t upper)
   {
   return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, {
      safe_get(rand_out) = Botan::BigInt::random_integer(r, safe_get(lower), safe_get(upper)); });
   }

int botan_mp_gcd(botan_mp_t out, const botan_mp_t x, const botan_mp_t y)
   {
   return BOTAN_FFI_DO(Botan::BigInt, out, o, {
      o = Botan::gcd(safe_get(x), safe_get(y)); });
   }

int botan_mp_is_prime(const botan_mp_t mp, botan_rng_t rng, size_t test_prob)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n,
                       { return (Botan::is_prime(n, safe_get(rng), test_prob)) ? 1 : 0; });
   }

int botan_mp_get_bit(const botan_mp_t mp, size_t bit)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n, { return (n.get_bit(bit)); });
   }

int botan_mp_set_bit(botan_mp_t mp, size_t bit)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.set_bit(bit); });
   }

int botan_mp_clear_bit(botan_mp_t mp, size_t bit)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n, { n.clear_bit(bit); });
   }

int botan_mp_num_bits(const botan_mp_t mp, size_t* bits)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bits = n.bits(); });
   }

int botan_mp_num_bytes(const botan_mp_t mp, size_t* bytes)
   {
   return BOTAN_FFI_DO(Botan::BigInt, mp, n, { *bytes = n.bytes(); });
   }

}