#![cfg_attr(not(feature = "rsa_signing"), allow(dead_code))]
use {bits, bssl, c, der, error, untrusted};
use core;
use core::marker::PhantomData;
pub fn verify_less_than<A: core::convert::AsRef<BIGNUM>,
B: core::convert::AsRef<BIGNUM>>(a: &A, b: &B)
-> Result<(), error::Unspecified> {
let r = unsafe { GFp_BN_cmp(a.as_ref(), b.as_ref()) };
if !(r < 0) {
return Err(error::Unspecified);
}
Ok(())
}
impl<F: Field> AsRef<BIGNUM> for Modulus<F> {
fn as_ref<'a>(&'a self) -> &'a BIGNUM {
unsafe { GFp_BN_MONT_CTX_get0_n(self.as_ref()) }
}
}
impl AsRef<BIGNUM> for OddPositive {
fn as_ref<'a>(&'a self) -> &'a BIGNUM { self.0.as_ref() }
}
impl AsRef<BIGNUM> for Positive {
fn as_ref<'a>(&'a self) -> &'a BIGNUM { self.0.as_ref() }
}
impl AsRef<BIGNUM> for Nonnegative {
fn as_ref<'a>(&'a self) -> &'a BIGNUM { unsafe { &*self.0 } }
}
pub struct Positive(Nonnegative);
impl Positive {
pub fn from_der(input: &mut untrusted::Reader)
-> Result<Positive, error::Unspecified> {
Self::from_be_bytes(try!(der::positive_integer(input)))
}
pub fn from_be_bytes(input: untrusted::Input)
-> Result<Positive, error::Unspecified> {
if untrusted::Reader::new(input).peek(0) {
return Err(error::Unspecified);
}
Self::from_be_bytes_padded(input)
}
pub fn from_be_bytes_padded(input: untrusted::Input)
-> Result<Positive, error::Unspecified> {
if input.is_empty() {
return Err(error::Unspecified);
}
let value = unsafe {
GFp_BN_bin2bn(input.as_slice_less_safe().as_ptr(), input.len(),
core::ptr::null_mut())
};
if value.is_null() {
return Err(error::Unspecified);
}
let r = Nonnegative(value);
if r.is_zero() {
return Err(error::Unspecified);
}
Ok(Positive(r))
}
pub fn into_elem<F: Field>(mut self, m: &Modulus<F>)
-> Result<Elem<F>, error::Unspecified> {
try!(verify_less_than(&self, &m));
try!(bssl::map_result(unsafe {
GFp_BN_to_mont(self.0.as_mut_ref(), self.as_ref(), m.as_ref())
}));
Ok(Elem {
value: self.0,
field: PhantomData,
})
}
pub fn into_elem_decoded<F: Field>(self, m: &Modulus<F>)
-> Result<ElemDecoded<F>, error::Unspecified> {
try!(verify_less_than(&self, &m));
Ok(ElemDecoded {
value: self.0,
field: PhantomData,
})
}
pub fn into_odd_positive(self) -> Result<OddPositive, error::Unspecified> {
self.0.into_odd_positive()
}
pub fn bit_length(&self) -> bits::BitLength {
let bits = unsafe { GFp_BN_num_bits(self.as_ref()) };
bits::BitLength::from_usize_bits(bits)
}
}
pub struct OddPositive(Positive);
impl OddPositive {
pub fn try_clone(&self) -> Result<OddPositive, error::Unspecified> {
let mut value = try!(Nonnegative::zero());
try!(bssl::map_result(unsafe {
GFp_BN_copy(value.as_mut_ref(), self.as_ref())
}));
Ok(OddPositive(Positive(value)))
}
pub fn into_elem<F: Field>(self, m: &Modulus<F>)
-> Result<Elem<F>, error::Unspecified> {
self.0.into_elem(m)
}
pub fn into_elem_decoded<F: Field>(self, m: &Modulus<F>)
-> Result<ElemDecoded<F>, error::Unspecified> {
self.0.into_elem_decoded(m)
}
pub fn into_modulus<F: Field>(self)
-> Result<Modulus<F>, error::Unspecified> {
let r = Modulus {
ctx: unsafe { GFp_BN_MONT_CTX_new() },
field: PhantomData,
};
if r.ctx.is_null() {
return Err(error::Unspecified);
}
try!(bssl::map_result(unsafe {
GFp_BN_MONT_CTX_set(&mut *r.ctx, self.as_ref())
}));
Ok(r)
}
}
impl core::ops::Deref for OddPositive {
type Target = Positive;
fn deref(&self) -> &Self::Target { &self.0 }
}
pub unsafe trait Field {}
pub struct Modulus<F: Field> {
ctx: *mut BN_MONT_CTX,
field: PhantomData<F>,
}
impl<F: Field> Modulus<F> {
pub fn as_ref(&self) -> &BN_MONT_CTX { unsafe { &*self.ctx } }
}
impl<F: Field> Drop for Modulus<F> {
fn drop(&mut self) { unsafe { GFp_BN_MONT_CTX_free(self.ctx); } }
}
pub struct Elem<F: Field> {
value: Nonnegative,
field: PhantomData<F>,
}
impl<F: Field> Elem<F> {
pub fn as_ref_montgomery_encoded<'a>(&'a self) -> &'a BIGNUM {
self.value.as_ref()
}
}
pub struct ElemDecoded<F: Field> {
value: Nonnegative,
field: PhantomData<F>
}
impl<F: Field> ElemDecoded<F> {
pub fn fill_be_bytes(&self, out: &mut [u8])
-> Result<(), error::Unspecified> {
bssl::map_result(unsafe {
GFp_BN_bn2bin_padded(out.as_mut_ptr(), out.len(),
self.value.as_ref())
})
}
pub fn is_zero(&self) -> bool { self.value.is_zero() }
pub fn is_one(&self) -> bool { self.value.is_one() }
pub unsafe fn as_mut_ref<'a>(&'a mut self) -> &'a mut BIGNUM {
self.value.as_mut_ref()
}
pub fn into_odd_positive(self) -> Result<OddPositive, error::Unspecified> {
self.value.into_odd_positive()
}
}
pub fn elem_mul_mixed<F: Field>(a: &Elem<F>, b: &ElemDecoded<F>, m: &Modulus<F>)
-> Result<ElemDecoded<F>, error::Unspecified> {
let mut r = try!(Nonnegative::zero());
try!(bssl::map_result(unsafe {
GFp_BN_mod_mul_mont(r.as_mut_ref(), a.value.as_ref(),
b.value.as_ref(), m.as_ref())
}));
Ok(ElemDecoded {
value: r,
field: PhantomData
})
}
struct Nonnegative(*mut BIGNUM);
impl Nonnegative {
fn zero() -> Result<Self, error::Unspecified> {
let r = Nonnegative(unsafe { GFp_BN_new() });
if r.0.is_null() {
return Err(error::Unspecified);
}
debug_assert!(r.is_zero());
Ok(r)
}
fn is_zero(&self) -> bool {
let is_zero = unsafe { GFp_BN_is_zero(self.as_ref()) };
is_zero != 0
}
fn is_one(&self) -> bool {
let is_one = unsafe { GFp_BN_is_one(self.as_ref()) };
is_one != 0
}
unsafe fn as_mut_ref(&mut self) -> &mut BIGNUM { &mut *self.0 }
fn into_odd_positive(self) -> Result<OddPositive, error::Unspecified> {
let is_odd = unsafe { GFp_BN_is_odd(self.as_ref()) };
if is_odd == 0 {
return Err(error::Unspecified);
}
Ok(OddPositive(Positive(self)))
}
}
impl Drop for Nonnegative {
fn drop(&mut self) { unsafe { GFp_BN_free(self.0); } }
}
#[allow(non_camel_case_types)]
pub enum BN_MONT_CTX {}
pub enum BIGNUM {}
extern {
fn GFp_BN_new() -> *mut BIGNUM;
fn GFp_BN_bin2bn(in_: *const u8, len: c::size_t, ret: *mut BIGNUM)
-> *mut BIGNUM;
fn GFp_BN_bn2bin_padded(out_: *mut u8, len: c::size_t, in_: &BIGNUM)
-> c::int;
fn GFp_BN_cmp(a: &BIGNUM, b: &BIGNUM) -> c::int;
fn GFp_BN_is_odd(a: &BIGNUM) -> c::int;
fn GFp_BN_is_zero(a: &BIGNUM) -> c::int;
fn GFp_BN_is_one(a: &BIGNUM) -> c::int;
fn GFp_BN_num_bits(bn: *const BIGNUM) -> c::size_t;
fn GFp_BN_free(bn: *mut BIGNUM);
fn GFp_BN_to_mont(r: *mut BIGNUM, a: *const BIGNUM, m: &BN_MONT_CTX)
-> c::int;
fn GFp_BN_copy(a: &mut BIGNUM, b: &BIGNUM) -> c::int;
fn GFp_BN_mod_mul_mont(r: &mut BIGNUM, a: &BIGNUM, b: &BIGNUM,
m: &BN_MONT_CTX) -> c::int;
fn GFp_BN_MONT_CTX_new() -> *mut BN_MONT_CTX;
fn GFp_BN_MONT_CTX_set(ctx: &mut BN_MONT_CTX, modulus: &BIGNUM) -> c::int;
fn GFp_BN_MONT_CTX_get0_n<'a>(ctx: &'a BN_MONT_CTX) -> &'a BIGNUM;
fn GFp_BN_MONT_CTX_free(mont: *mut BN_MONT_CTX);
}
#[cfg(test)]
mod tests {
use super::Positive;
use untrusted;
#[test]
fn test_positive_integer_from_be_bytes_empty() {
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[])).is_err());
}
#[test]
fn test_positive_integer_from_be_bytes_zero() {
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[0])).is_err());
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[0, 0])).is_err());
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[0, 1])).is_err());
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[1])).is_ok());
assert!(Positive::from_be_bytes(
untrusted::Input::from(&[1, 0])).is_ok());
}
}