1use std::{cmp::Ordering, fmt, ops, ptr, str};
2
3use cstr_argument::CStrArgument;
4use ffi;
5use libc::c_uint;
6
7use crate::{buffer::Buffer, error::return_err, rand::Level, Error, NonNull, Result};
8
9#[repr(usize)]
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Format {
12 Standard = ffi::GCRYMPI_FMT_STD as usize,
13 Unsigned = ffi::GCRYMPI_FMT_USG as usize,
14 Pgp = ffi::GCRYMPI_FMT_PGP as usize,
15 Ssh = ffi::GCRYMPI_FMT_SSH as usize,
16 Hex = ffi::GCRYMPI_FMT_HEX as usize,
17}
18
19pub struct Integer(NonNull<ffi::gcry_mpi_t>);
20
21impl Drop for Integer {
22 #[inline]
23 fn drop(&mut self) {
24 unsafe {
25 ffi::gcry_mpi_release(self.as_raw());
26 }
27 }
28}
29
30impl Clone for Integer {
31 #[inline]
32 fn clone(&self) -> Integer {
33 unsafe { Integer::from_raw(ffi::gcry_mpi_copy(self.as_raw())) }
34 }
35
36 #[inline]
37 fn clone_from(&mut self, source: &Integer) {
38 unsafe {
39 ffi::gcry_mpi_set(self.as_raw(), source.as_raw());
40 }
41 }
42}
43
44impl Integer {
45 impl_wrapper!(Integer: ffi::gcry_mpi_t);
46
47 #[inline]
48 pub fn zero() -> Integer {
49 Integer::new(0)
50 }
51
52 #[inline]
53 pub fn one() -> Integer {
54 Integer::from_uint(1)
55 }
56
57 #[inline]
58 pub fn new(nbits: u32) -> Integer {
59 let _ = crate::init_default();
60 unsafe { Integer::from_raw(ffi::gcry_mpi_new(nbits.into())) }
61 }
62
63 #[inline]
64 pub fn new_secure(nbits: u32) -> Integer {
65 let _ = crate::init_default();
66 unsafe { Integer::from_raw(ffi::gcry_mpi_snew(nbits.into())) }
67 }
68
69 #[inline]
70 pub fn from_uint(n: u32) -> Integer {
71 let _ = crate::init_default();
72 unsafe { Integer::from_raw(ffi::gcry_mpi_set_ui(ptr::null_mut(), n.into())) }
73 }
74
75 #[inline]
76 pub fn from_bytes(format: Format, bytes: impl AsRef<[u8]>) -> Result<Integer> {
77 let bytes = bytes.as_ref();
78 let _ = crate::init_default();
79 unsafe {
80 let mut raw = ptr::null_mut();
81 let len = if format != Format::Hex {
82 bytes.len()
83 } else if bytes.contains(&0) {
84 0
85 } else {
86 return Err(Error::INV_ARG);
87 };
88 return_err!(ffi::gcry_mpi_scan(
89 &mut raw,
90 format as ffi::gcry_mpi_format,
91 bytes.as_ptr().cast(),
92 len,
93 ptr::null_mut()
94 ));
95 Ok(Integer::from_raw(raw))
96 }
97 }
98
99 #[inline]
100 pub fn from_str(s: impl CStrArgument) -> Result<Integer> {
101 let s = s.into_cstr();
102 Integer::from_bytes(Format::Hex, s.as_ref().to_bytes_with_nul())
103 }
104
105 #[inline]
106 pub fn to_bytes(&self, format: Format) -> Result<Buffer> {
107 unsafe {
108 let mut buffer = ptr::null_mut();
109 let mut len = 0;
110 return_err!(ffi::gcry_mpi_aprint(
111 format as ffi::gcry_mpi_format,
112 &mut buffer,
113 &mut len,
114 self.as_raw()
115 ));
116 Ok(Buffer::from_raw(buffer.cast(), len))
117 }
118 }
119
120 #[inline]
121 pub fn len_encoded(&self, format: Format) -> Result<usize> {
122 unsafe {
123 let mut len = 0;
124 return_err!(ffi::gcry_mpi_print(
125 format as ffi::gcry_mpi_format,
126 ptr::null_mut(),
127 0,
128 &mut len,
129 self.as_raw()
130 ));
131 Ok(len)
132 }
133 }
134
135 #[inline]
136 pub fn encode(&self, format: Format, buf: &mut [u8]) -> Result<usize> {
137 unsafe {
138 let mut written = 0;
139 return_err!(ffi::gcry_mpi_print(
140 format as ffi::gcry_mpi_format,
141 buf.as_mut_ptr().cast(),
142 buf.len(),
143 &mut written,
144 self.as_raw()
145 ));
146 Ok(written)
147 }
148 }
149
150 #[inline]
151 pub fn set(&mut self, n: u32) {
152 unsafe {
153 ffi::gcry_mpi_set_ui(self.as_raw(), n.into());
154 }
155 }
156
157 #[inline]
158 pub fn randomize(&mut self, nbits: u32, level: Level) {
159 unsafe {
160 ffi::gcry_mpi_randomize(self.as_raw(), nbits.into(), level.raw());
161 }
162 }
163
164 #[inline]
165 pub fn num_bits(&self) -> usize {
166 unsafe { ffi::gcry_mpi_get_nbits(self.as_raw()) as usize }
167 }
168
169 #[inline]
170 pub fn is_prime(&self) -> bool {
171 unsafe { ffi::gcry_prime_check(self.as_raw(), 0) == 0 }
172 }
173
174 #[inline]
175 pub fn is_positive(&self) -> bool {
176 unsafe { ffi::gcry_mpi_cmp_ui(self.as_raw(), 0) > 0 }
177 }
178
179 #[inline]
180 pub fn is_negative(&self) -> bool {
181 unsafe { ffi::gcry_mpi_cmp_ui(self.as_raw(), 0) < 0 }
182 }
183
184 #[inline]
185 pub fn abs(self) -> Integer {
186 unsafe {
187 ffi::gcry_mpi_abs(self.as_raw());
188 }
189 self
190 }
191
192 #[inline]
193 pub fn add_mod(self, other: &Integer, m: &Integer) -> Integer {
194 unsafe {
195 ffi::gcry_mpi_addm(self.as_raw(), self.as_raw(), other.as_raw(), m.as_raw());
196 }
197 self
198 }
199
200 #[inline]
201 pub fn sub_mod(self, other: &Integer, m: &Integer) -> Integer {
202 unsafe {
203 ffi::gcry_mpi_subm(self.as_raw(), self.as_raw(), other.as_raw(), m.as_raw());
204 }
205 self
206 }
207
208 #[inline]
209 pub fn mul_mod(self, other: &Integer, m: &Integer) -> Integer {
210 unsafe {
211 ffi::gcry_mpi_mulm(self.as_raw(), self.as_raw(), other.as_raw(), m.as_raw());
212 }
213 self
214 }
215
216 #[inline]
217 pub fn inv_mod(self, m: &Integer) -> Option<Integer> {
218 let result = unsafe { ffi::gcry_mpi_invm(self.as_raw(), self.as_raw(), m.as_raw()) };
219 if result != 0 {
220 Some(self)
221 } else {
222 None
223 }
224 }
225
226 #[inline]
227 pub fn div_floor(self, other: &Integer) -> Integer {
228 unsafe {
229 ffi::gcry_mpi_div(
230 self.as_raw(),
231 ptr::null_mut(),
232 self.as_raw(),
233 other.as_raw(),
234 -1,
235 );
236 }
237 self
238 }
239
240 #[inline]
241 pub fn mod_floor(self, other: &Integer) -> Integer {
242 unsafe {
243 ffi::gcry_mpi_div(
244 ptr::null_mut(),
245 self.as_raw(),
246 self.as_raw(),
247 other.as_raw(),
248 -1,
249 );
250 }
251 self
252 }
253
254 #[inline]
255 pub fn div_rem(self, other: &Integer) -> (Integer, Integer) {
256 let rem = Integer::zero();
257 unsafe {
258 ffi::gcry_mpi_div(
259 self.as_raw(),
260 rem.as_raw(),
261 self.as_raw(),
262 other.as_raw(),
263 0,
264 );
265 }
266 (self, rem)
267 }
268
269 #[inline]
270 pub fn div_mod_floor(self, other: &Integer) -> (Integer, Integer) {
271 let rem = Integer::zero();
272 unsafe {
273 ffi::gcry_mpi_div(
274 self.as_raw(),
275 rem.as_raw(),
276 self.as_raw(),
277 other.as_raw(),
278 -1,
279 );
280 }
281 (self, rem)
282 }
283
284 #[inline]
285 pub fn ldexp(self, e: u32) -> Integer {
286 unsafe {
287 ffi::gcry_mpi_mul_2exp(self.as_raw(), self.as_raw(), e.into());
288 }
289 self
290 }
291
292 #[inline]
293 pub fn pow_mod(self, e: &Integer, m: &Integer) -> Integer {
294 unsafe {
295 ffi::gcry_mpi_powm(self.as_raw(), self.as_raw(), e.as_raw(), m.as_raw());
296 }
297 self
298 }
299
300 #[inline]
301 pub fn gcd(self, other: &Integer) -> Integer {
302 unsafe {
303 ffi::gcry_mpi_gcd(self.as_raw(), self.as_raw(), other.as_raw());
304 }
305 self
306 }
307
308 #[inline]
309 pub fn lcm(self, other: &Integer) -> Integer {
310 (self.clone() * other) / self.gcd(other)
311 }
312}
313
314impl Default for Integer {
315 #[inline]
316 fn default() -> Self {
317 Self::zero()
318 }
319}
320
321impl From<u32> for Integer {
322 #[inline]
323 fn from(x: u32) -> Self {
324 Self::from_uint(x)
325 }
326}
327
328impl fmt::Debug for Integer {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 let mut s = f.debug_struct("Integer");
331 s.field("raw", &self.0);
332 if let Ok(bytes) = self.to_bytes(Format::Hex) {
333 s.field("hex", &str::from_utf8(&bytes[..(bytes.len() - 1)]).unwrap());
334 }
335 s.finish()
336 }
337}
338
339impl PartialEq<u32> for Integer {
340 #[inline]
341 fn eq(&self, other: &u32) -> bool {
342 self.partial_cmp(other).unwrap() == Ordering::Equal
343 }
344}
345
346impl PartialEq<Integer> for u32 {
347 #[inline]
348 fn eq(&self, other: &Integer) -> bool {
349 self.partial_cmp(other).unwrap() == Ordering::Equal
350 }
351}
352
353impl PartialOrd<u32> for Integer {
354 #[inline]
355 fn partial_cmp(&self, other: &u32) -> Option<Ordering> {
356 let result = unsafe { ffi::gcry_mpi_cmp_ui(self.as_raw(), (*other).into()) };
357 match result {
358 x if x < 0 => Some(Ordering::Less),
359 x if x > 0 => Some(Ordering::Greater),
360 _ => Some(Ordering::Equal),
361 }
362 }
363}
364
365impl PartialOrd<Integer> for u32 {
366 #[inline]
367 fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
368 other.partial_cmp(self).map(Ordering::reverse)
369 }
370}
371
372impl PartialEq for Integer {
373 #[inline]
374 fn eq(&self, other: &Integer) -> bool {
375 self.cmp(other) == Ordering::Equal
376 }
377}
378impl Eq for Integer {}
379
380impl PartialOrd for Integer {
381 #[inline]
382 fn partial_cmp(&self, other: &Integer) -> Option<Ordering> {
383 Some(self.cmp(other))
384 }
385}
386impl Ord for Integer {
387 #[inline]
388 fn cmp(&self, other: &Integer) -> Ordering {
389 let result = unsafe { ffi::gcry_mpi_cmp(self.as_raw(), other.as_raw()) };
390 match result {
391 x if x < 0 => Ordering::Less,
392 x if x > 0 => Ordering::Greater,
393 _ => Ordering::Equal,
394 }
395 }
396}
397
398impl ops::Neg for Integer {
399 type Output = Integer;
400
401 #[inline]
402 fn neg(self) -> Integer {
403 unsafe {
404 ffi::gcry_mpi_neg(self.as_raw(), self.as_raw());
405 }
406 self
407 }
408}
409
410impl ops::Neg for &'_ Integer {
411 type Output = Integer;
412
413 #[inline]
414 fn neg(self) -> Integer {
415 self.clone().neg()
416 }
417}
418
419macro_rules! impl_binary_op {
420 ($imp:ident, $method:ident, $body:expr) => {
421 impl ops::$imp for Integer {
422 type Output = Integer;
423
424 #[inline]
425 fn $method(self, other: Integer) -> Integer {
426 self.$method(&other)
427 }
428 }
429 impl<'a> ops::$imp<Integer> for &'a Integer {
430 type Output = Integer;
431
432 #[inline]
433 fn $method(self, other: Integer) -> Integer {
434 self.clone().$method(&other)
435 }
436 }
437
438 impl<'a> ops::$imp<&'a Integer> for Integer {
439 type Output = Integer;
440
441 #[inline]
442 fn $method(self, other: &'a Integer) -> Integer {
443 unsafe {
444 $body(self.as_raw(), other.as_raw());
445 }
446 self
447 }
448 }
449 };
450}
451impl_binary_op!(Add, add, |x, y| ffi::gcry_mpi_add(x, x, y));
452impl_binary_op!(Sub, sub, |x, y| ffi::gcry_mpi_sub(x, x, y));
453impl_binary_op!(Mul, mul, |x, y| ffi::gcry_mpi_mul(x, x, y));
454impl_binary_op!(Div, div, |x, y| ffi::gcry_mpi_div(
455 x,
456 ptr::null_mut(),
457 x,
458 y,
459 0
460));
461impl_binary_op!(Rem, rem, |x, y| ffi::gcry_mpi_mod(x, x, y));
462
463impl ops::Shl<usize> for Integer {
464 type Output = Integer;
465
466 #[inline]
467 fn shl(self, other: usize) -> Integer {
468 unsafe {
469 ffi::gcry_mpi_lshift(self.as_raw(), self.as_raw(), other as c_uint);
470 }
471 self
472 }
473}
474
475impl ops::Shr<usize> for Integer {
476 type Output = Integer;
477
478 #[inline]
479 fn shr(self, other: usize) -> Integer {
480 unsafe {
481 ffi::gcry_mpi_rshift(self.as_raw(), self.as_raw(), other as c_uint);
482 }
483 self
484 }
485}