use ffi;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_int;
use std::cmp::Ordering;
use std::ffi::CString;
use std::{fmt, ptr};
use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref};
use {cvt, cvt_p, cvt_n};
use asn1::Asn1Integer;
use error::ErrorStack;
use string::OpensslString;
#[cfg(ossl10x)]
use ffi::{get_rfc2409_prime_768 as BN_get_rfc2409_prime_768,
get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024,
get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536,
get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048,
get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072,
get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096,
get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144,
get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192};
#[cfg(ossl110)]
use ffi::{BN_get_rfc2409_prime_768, BN_get_rfc2409_prime_1024, BN_get_rfc3526_prime_1536,
BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096,
BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192};
pub struct MsbOption(c_int);
pub const MSB_MAYBE_ZERO: MsbOption = MsbOption(-1);
pub const MSB_ONE: MsbOption = MsbOption(0);
pub const TWO_MSB_ONE: MsbOption = MsbOption(1);
foreign_type! {
type CType = ffi::BN_CTX;
fn drop = ffi::BN_CTX_free;
pub struct BigNumContext;
pub struct BigNumContextRef;
}
impl BigNumContext {
pub fn new() -> Result<BigNumContext, ErrorStack> {
unsafe {
ffi::init();
cvt_p(ffi::BN_CTX_new()).map(BigNumContext)
}
}
}
impl BigNumRef {
pub fn clear(&mut self) {
unsafe { ffi::BN_clear(self.as_ptr()) }
}
pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
}
pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
}
pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) }
}
pub fn div_word(&mut self, w: u32) -> Result<u64, ErrorStack> {
unsafe {
let r = ffi::BN_div_word(self.as_ptr(), w.into());
if r == ffi::BN_ULONG::max_value() {
Err(ErrorStack::get())
} else {
Ok(r.into())
}
}
}
pub fn mod_word(&self, w: u32) -> Result<u64, ErrorStack> {
unsafe {
let r = ffi::BN_mod_word(self.as_ptr(), w.into());
if r == ffi::BN_ULONG::max_value() {
Err(ErrorStack::get())
} else {
Ok(r.into())
}
}
}
pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) }
}
pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) }
}
pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) }
}
pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) }
}
pub fn is_bit_set(&self, n: i32) -> bool {
unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 }
}
pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) }
}
pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
}
pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) }
}
pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
}
pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) }
}
pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
}
pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) }
}
pub fn to_owned(&self) -> Result<BigNum, ErrorStack> {
unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) }
}
pub fn set_negative(&mut self, negative: bool) {
unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) }
}
pub fn ucmp(&self, oth: &BigNumRef) -> Ordering {
unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
}
pub fn is_negative(&self) -> bool {
self._is_negative()
}
#[cfg(ossl10x)]
fn _is_negative(&self) -> bool {
unsafe { (*self.as_ptr()).neg == 1 }
}
#[cfg(ossl110)]
fn _is_negative(&self) -> bool {
unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 }
}
pub fn num_bits(&self) -> i32 {
unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 }
}
pub fn num_bytes(&self) -> i32 {
(self.num_bits() + 7) / 8
}
pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_rand(
self.as_ptr(),
bits.into(),
msb.0,
odd as c_int,
)).map(|_| ())
}
}
pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_pseudo_rand(
self.as_ptr(),
bits.into(),
msb.0,
odd as c_int,
)).map(|_| ())
}
}
pub fn generate_prime(
&mut self,
bits: i32,
safe: bool,
add: Option<&BigNumRef>,
rem: Option<&BigNumRef>,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_generate_prime_ex(
self.as_ptr(),
bits as c_int,
safe as c_int,
add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()),
ptr::null_mut(),
)).map(|_| ())
}
}
pub fn checked_mul(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mul(
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn checked_div(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_div(
self.as_ptr(),
ptr::null_mut(),
a.as_ptr(),
b.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn checked_rem(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_div(
ptr::null_mut(),
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn div_rem(
&mut self,
rem: &mut BigNumRef,
a: &BigNumRef,
b: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_div(
self.as_ptr(),
rem.as_ptr(),
a.as_ptr(),
b.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) }
}
pub fn nnmod(
&mut self,
a: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_nnmod(
self.as_ptr(),
a.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_add(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mod_add(
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_sub(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mod_sub(
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_mul(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mod_mul(
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_sqr(
&mut self,
a: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mod_sqr(
self.as_ptr(),
a.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn exp(
&mut self,
a: &BigNumRef,
p: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_exp(
self.as_ptr(),
a.as_ptr(),
p.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_exp(
&mut self,
a: &BigNumRef,
p: &BigNumRef,
m: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_mod_exp(
self.as_ptr(),
a.as_ptr(),
p.as_ptr(),
m.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn mod_inverse(
&mut self,
a: &BigNumRef,
n: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt_p(ffi::BN_mod_inverse(
self.as_ptr(),
a.as_ptr(),
n.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn gcd(
&mut self,
a: &BigNumRef,
b: &BigNumRef,
ctx: &mut BigNumContextRef,
) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::BN_gcd(
self.as_ptr(),
a.as_ptr(),
b.as_ptr(),
ctx.as_ptr(),
)).map(|_| ())
}
}
pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result<bool, ErrorStack> {
unsafe {
cvt_n(ffi::BN_is_prime_ex(
self.as_ptr(),
checks.into(),
ctx.as_ptr(),
ptr::null_mut(),
)).map(|r| r != 0)
}
}
pub fn is_prime_fasttest(
&self,
checks: i32,
ctx: &mut BigNumContextRef,
do_trial_division: bool,
) -> Result<bool, ErrorStack> {
unsafe {
cvt_n(ffi::BN_is_prime_fasttest_ex(
self.as_ptr(),
checks.into(),
ctx.as_ptr(),
do_trial_division as c_int,
ptr::null_mut(),
)).map(|r| r != 0)
}
}
pub fn to_vec(&self) -> Vec<u8> {
let size = self.num_bytes() as usize;
let mut v = Vec::with_capacity(size);
unsafe {
ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr());
v.set_len(size);
}
v
}
pub fn to_dec_str(&self) -> Result<OpensslString, ErrorStack> {
unsafe {
let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr())));
Ok(OpensslString::from_ptr(buf))
}
}
pub fn to_hex_str(&self) -> Result<OpensslString, ErrorStack> {
unsafe {
let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr())));
Ok(OpensslString::from_ptr(buf))
}
}
pub fn to_asn1_integer(&self) -> Result<Asn1Integer, ErrorStack> {
unsafe {
cvt_p(ffi::BN_to_ASN1_INTEGER(self.as_ptr(), ptr::null_mut()))
.map(|p| Asn1Integer::from_ptr(p))
}
}
}
foreign_type! {
type CType = ffi::BIGNUM;
fn drop = ffi::BN_free;
pub struct BigNum;
pub struct BigNumRef;
}
impl BigNum {
pub fn new() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
let v = try!(cvt_p(ffi::BN_new()));
Ok(BigNum::from_ptr(v))
}
}
pub fn from_u32(n: u32) -> Result<BigNum, ErrorStack> {
BigNum::new().and_then(|v| unsafe {
cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v)
})
}
pub fn from_dec_str(s: &str) -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
let c_str = CString::new(s.as_bytes()).unwrap();
let mut bn = ptr::null_mut();
try!(cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _)));
Ok(BigNum::from_ptr(bn))
}
}
pub fn from_hex_str(s: &str) -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
let c_str = CString::new(s.as_bytes()).unwrap();
let mut bn = ptr::null_mut();
try!(cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _)));
Ok(BigNum::from_ptr(bn))
}
}
pub fn get_rfc2409_prime_768() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc2409_prime_768(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc2409_prime_1024() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc2409_prime_1024(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_1536() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_1536(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_2048() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_2048(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_3072() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_3072(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_4096() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_4096(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_6144() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_6144(ptr::null_mut())).map(BigNum)
}
}
pub fn get_rfc3526_prime_8192() -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
cvt_p(BN_get_rfc3526_prime_8192(ptr::null_mut())).map(BigNum)
}
}
pub fn from_slice(n: &[u8]) -> Result<BigNum, ErrorStack> {
unsafe {
ffi::init();
assert!(n.len() <= c_int::max_value() as usize);
cvt_p(ffi::BN_bin2bn(
n.as_ptr(),
n.len() as c_int,
ptr::null_mut(),
)).map(|p| BigNum::from_ptr(p))
}
}
}
impl AsRef<BigNumRef> for BigNum {
fn as_ref(&self) -> &BigNumRef {
self.deref()
}
}
impl fmt::Debug for BigNumRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.to_dec_str() {
Ok(s) => f.write_str(&s),
Err(e) => Err(e.into()),
}
}
}
impl fmt::Debug for BigNum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.to_dec_str() {
Ok(s) => f.write_str(&s),
Err(e) => Err(e.into()),
}
}
}
impl fmt::Display for BigNumRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.to_dec_str() {
Ok(s) => f.write_str(&s),
Err(e) => Err(e.into()),
}
}
}
impl fmt::Display for BigNum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.to_dec_str() {
Ok(s) => f.write_str(&s),
Err(e) => Err(e.into()),
}
}
}
impl PartialEq<BigNumRef> for BigNumRef {
fn eq(&self, oth: &BigNumRef) -> bool {
self.cmp(oth) == Ordering::Equal
}
}
impl PartialEq<BigNum> for BigNumRef {
fn eq(&self, oth: &BigNum) -> bool {
self.eq(oth.deref())
}
}
impl Eq for BigNumRef {}
impl PartialEq for BigNum {
fn eq(&self, oth: &BigNum) -> bool {
self.deref().eq(oth)
}
}
impl PartialEq<BigNumRef> for BigNum {
fn eq(&self, oth: &BigNumRef) -> bool {
self.deref().eq(oth)
}
}
impl Eq for BigNum {}
impl PartialOrd<BigNumRef> for BigNumRef {
fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
Some(self.cmp(oth))
}
}
impl PartialOrd<BigNum> for BigNumRef {
fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
Some(self.cmp(oth.deref()))
}
}
impl Ord for BigNumRef {
fn cmp(&self, oth: &BigNumRef) -> Ordering {
unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) }
}
}
impl PartialOrd for BigNum {
fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
self.deref().partial_cmp(oth.deref())
}
}
impl PartialOrd<BigNumRef> for BigNum {
fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
self.deref().partial_cmp(oth)
}
}
impl Ord for BigNum {
fn cmp(&self, oth: &BigNum) -> Ordering {
self.deref().cmp(oth.deref())
}
}
macro_rules! delegate {
($t:ident, $m:ident) => {
impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef {
type Output = BigNum;
fn $m(self, oth: &BigNum) -> BigNum {
$t::$m(self, oth.deref())
}
}
impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum {
type Output = BigNum;
fn $m(self, oth: &BigNumRef) -> BigNum {
$t::$m(self.deref(), oth)
}
}
impl<'a, 'b> $t<&'b BigNum> for &'a BigNum {
type Output = BigNum;
fn $m(self, oth: &BigNum) -> BigNum {
$t::$m(self.deref(), oth.deref())
}
}
}
}
impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef {
type Output = BigNum;
fn add(self, oth: &BigNumRef) -> BigNum {
let mut r = BigNum::new().unwrap();
r.checked_add(self, oth).unwrap();
r
}
}
delegate!(Add, add);
impl<'a, 'b> Sub<&'b BigNumRef> for &'a BigNumRef {
type Output = BigNum;
fn sub(self, oth: &BigNumRef) -> BigNum {
let mut r = BigNum::new().unwrap();
r.checked_sub(self, oth).unwrap();
r
}
}
delegate!(Sub, sub);
impl<'a, 'b> Mul<&'b BigNumRef> for &'a BigNumRef {
type Output = BigNum;
fn mul(self, oth: &BigNumRef) -> BigNum {
let mut ctx = BigNumContext::new().unwrap();
let mut r = BigNum::new().unwrap();
r.checked_mul(self, oth, &mut ctx).unwrap();
r
}
}
delegate!(Mul, mul);
impl<'a, 'b> Div<&'b BigNumRef> for &'a BigNumRef {
type Output = BigNum;
fn div(self, oth: &'b BigNumRef) -> BigNum {
let mut ctx = BigNumContext::new().unwrap();
let mut r = BigNum::new().unwrap();
r.checked_div(self, oth, &mut ctx).unwrap();
r
}
}
delegate!(Div, div);
impl<'a, 'b> Rem<&'b BigNumRef> for &'a BigNumRef {
type Output = BigNum;
fn rem(self, oth: &'b BigNumRef) -> BigNum {
let mut ctx = BigNumContext::new().unwrap();
let mut r = BigNum::new().unwrap();
r.checked_rem(self, oth, &mut ctx).unwrap();
r
}
}
delegate!(Rem, rem);
impl<'a> Shl<i32> for &'a BigNumRef {
type Output = BigNum;
fn shl(self, n: i32) -> BigNum {
let mut r = BigNum::new().unwrap();
r.lshift(self, n).unwrap();
r
}
}
impl<'a> Shl<i32> for &'a BigNum {
type Output = BigNum;
fn shl(self, n: i32) -> BigNum {
self.deref().shl(n)
}
}
impl<'a> Shr<i32> for &'a BigNumRef {
type Output = BigNum;
fn shr(self, n: i32) -> BigNum {
let mut r = BigNum::new().unwrap();
r.rshift(self, n).unwrap();
r
}
}
impl<'a> Shr<i32> for &'a BigNum {
type Output = BigNum;
fn shr(self, n: i32) -> BigNum {
self.deref().shr(n)
}
}
impl<'a> Neg for &'a BigNumRef {
type Output = BigNum;
fn neg(self) -> BigNum {
self.to_owned().unwrap().neg()
}
}
impl<'a> Neg for &'a BigNum {
type Output = BigNum;
fn neg(self) -> BigNum {
self.deref().neg()
}
}
impl Neg for BigNum {
type Output = BigNum;
fn neg(mut self) -> BigNum {
let negative = self.is_negative();
self.set_negative(!negative);
self
}
}
#[cfg(test)]
mod tests {
use bn::{BigNumContext, BigNum};
#[test]
fn test_to_from_slice() {
let v0 = BigNum::from_u32(10203004).unwrap();
let vec = v0.to_vec();
let v1 = BigNum::from_slice(&vec).unwrap();
assert!(v0 == v1);
}
#[test]
fn test_negation() {
let a = BigNum::from_u32(909829283).unwrap();
assert!(!a.is_negative());
assert!((-a).is_negative());
}
#[test]
fn test_shift() {
let a = BigNum::from_u32(909829283).unwrap();
use std::ops::{Shl, Shr};
assert!(a == a.shl(1).shr(1));
}
#[test]
fn test_rand_range() {
let range = BigNum::from_u32(909829283).unwrap();
let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap();
range.rand_range(&mut result).unwrap();
assert!(result >= BigNum::from_u32(0).unwrap() && result < range);
}
#[test]
fn test_pseudo_rand_range() {
let range = BigNum::from_u32(909829283).unwrap();
let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap();
range.pseudo_rand_range(&mut result).unwrap();
assert!(result >= BigNum::from_u32(0).unwrap() && result < range);
}
#[test]
fn test_prime_numbers() {
let a = BigNum::from_u32(19029017).unwrap();
let mut p = BigNum::new().unwrap();
p.generate_prime(128, true, None, Some(&a)).unwrap();
let mut ctx = BigNumContext::new().unwrap();
assert!(p.is_prime(100, &mut ctx).unwrap());
assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap());
}
}