diff --git a/Cargo.toml b/Cargo.toml index 196ee0dd..d4e20cac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,6 @@ sha2 = "0.8.0" sha3 = "0.8.2" zeroize = "1" -rust-gmp-kzen = { version = "0.5", features = ["serde_support"], optional = true } num-bigint = { version = "0.4", features = ["serde"], optional = true } [dependencies.secp256k1] @@ -46,6 +45,12 @@ features = ["serde", "rand-std"] version = "0.5" features = ["ecdsa"] +[dependencies.rug] +version = "1" +default-features = false +features = ["integer", "serde"] +optional = true + [dev-dependencies] bincode = "1.1" serde_json = "1.0" @@ -54,4 +59,4 @@ proptest = "0.10" proptest-derive = "0.2" [features] -default = ["rust-gmp-kzen"] +default = ["rug"] diff --git a/src/arithmetic/big_gmp.rs b/src/arithmetic/big_gmp.rs deleted file mode 100644 index 4526174f..00000000 --- a/src/arithmetic/big_gmp.rs +++ /dev/null @@ -1,432 +0,0 @@ -/* - Curv - - Copyright 2018 by Kzen Networks - - This file is part of Cryptography utilities library - (https://github.com/KZen-networks/cryptography-utils) - - Cryptography utilities is free software: you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation, either - version 3 of the License, or (at your option) any later version. - - @license GPL-3.0+ -*/ - -use std::convert::{TryFrom, TryInto}; -use std::sync::atomic; -use std::{fmt, ops, ptr}; - -use gmp::mpz::Mpz; -use gmp::sign::Sign; -use num_traits::{One, Zero}; -use serde::{Deserialize, Serialize}; -use zeroize::Zeroize; - -use super::errors::*; -use super::traits::*; - -type BN = Mpz; - -/// Big integer -/// -/// Wraps underlying BigInt implementation (either GMP bindings or num-bigint), exposes only -/// very limited API that allows easily switching between implementations. -/// -/// Set of traits implemented on BigInt remains the same regardless of underlying implementation. -#[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Serialize, Deserialize)] -#[serde(transparent)] -pub struct BigInt { - gmp: Mpz, -} - -impl BigInt { - fn inner_ref(&self) -> &Mpz { - &self.gmp - } - fn inner_mut(&mut self) -> &mut Mpz { - &mut self.gmp - } - fn into_inner(self) -> Mpz { - self.gmp - } -} - -#[allow(deprecated)] -impl ZeroizeBN for BigInt { - fn zeroize_bn(&mut self) { - unsafe { ptr::write_volatile(&mut self.gmp, Mpz::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl Zeroize for BigInt { - fn zeroize(&mut self) { - unsafe { ptr::write_volatile(&mut self.gmp, Mpz::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl Converter for BigInt { - fn to_bytes(&self) -> Vec { - (&self.gmp).into() - } - - fn from_bytes(bytes: &[u8]) -> Self { - Mpz::from(bytes).wrap() - } - - fn to_hex(&self) -> String { - self.gmp.to_str_radix(16) - } - - fn from_hex(value: &str) -> Result { - Mpz::from_str_radix(value, 16) - .map(Wrap::wrap) - .map_err(|e| ParseBigIntError { - reason: ParseErrorReason::Gmp(e), - radix: 16, - }) - } - - fn to_str_radix(&self, radix: u8) -> String { - self.gmp.to_str_radix(radix) - } - - fn from_str_radix(str: &str, radix: u8) -> Result { - Mpz::from_str_radix(str, radix) - .map(Wrap::wrap) - .map_err(|e| ParseBigIntError { - reason: ParseErrorReason::Gmp(e), - radix: radix.into(), - }) - } -} - -impl num_traits::Num for BigInt { - type FromStrRadixErr = ParseBigIntError; - fn from_str_radix(str: &str, radix: u32) -> Result { - ::from_str_radix(str, radix.try_into().unwrap()) - } -} - -impl BasicOps for BigInt { - fn pow(&self, exponent: u32) -> Self { - self.gmp.pow(exponent).wrap() - } - - fn mul(&self, other: &Self) -> Self { - self * other - } - - fn sub(&self, other: &Self) -> Self { - self - other - } - - fn add(&self, other: &Self) -> Self { - self + other - } - - fn abs(&self) -> Self { - self.gmp.abs().wrap() - } -} - -impl Primes for BigInt { - fn next_prime(&self) -> Self { - self.gmp.nextprime().wrap() - } - - fn is_probable_prime(&self, n: u32) -> bool { - use gmp::mpz::ProbabPrimeResult::*; - match self.gmp.probab_prime(n as i32) { - Prime | ProbablyPrime => true, - NotPrime => false, - } - } -} - -impl Modulo for BigInt { - fn mod_pow(base: &Self, exponent: &Self, modulus: &Self) -> Self { - assert!(exponent >= &BigInt::zero(), "exponent must be non-negative"); - base.gmp.powm(&exponent.gmp, &modulus.gmp).wrap() - } - - fn mod_mul(a: &Self, b: &Self, modulus: &Self) -> Self { - (a.gmp.mod_floor(&modulus.gmp) * b.gmp.mod_floor(&modulus.gmp)) - .mod_floor(&modulus.gmp) - .wrap() - } - - fn mod_sub(a: &Self, b: &Self, modulus: &Self) -> Self { - let a_m = a.gmp.mod_floor(&modulus.gmp); - let b_m = b.gmp.mod_floor(&modulus.gmp); - - let sub_op = a_m - b_m + &modulus.gmp; - sub_op.mod_floor(&modulus.gmp).wrap() - } - - fn mod_add(a: &Self, b: &Self, modulus: &Self) -> Self { - (a.gmp.mod_floor(&modulus.gmp) + b.gmp.mod_floor(&modulus.gmp)) - .mod_floor(&modulus.gmp) - .wrap() - } - - fn mod_inv(a: &Self, modulus: &Self) -> Option { - Some(a.gmp.invert(&modulus.gmp)?.wrap()) - } - - fn modulus(&self, modulus: &Self) -> Self { - self.gmp.modulus(&modulus.gmp).wrap() - } -} - -impl NumberTests for BigInt { - fn is_zero(me: &Self) -> bool { - me.gmp.is_zero() - } - fn is_negative(me: &Self) -> bool { - matches!(me.gmp.sign(), Sign::Negative) - } -} - -impl EGCD for BigInt { - #[allow(clippy::many_single_char_names)] - fn egcd(a: &Self, b: &Self) -> (Self, Self, Self) { - let (s, p, q) = a.gmp.gcdext(&b.gmp); - (s.wrap(), p.wrap(), q.wrap()) - } -} - -impl BitManipulation for BigInt { - fn set_bit(&mut self, bit: usize, bit_val: bool) { - if bit_val { - self.gmp.setbit(bit); - } else { - self.gmp.clrbit(bit); - } - } - - fn test_bit(&self, bit: usize) -> bool { - self.gmp.tstbit(bit) - } - - fn bit_length(&self) -> usize { - self.gmp.bit_length() - } -} - -impl Integer for BigInt { - fn div_floor(&self, other: &Self) -> Self { - self.gmp.div_floor(&other.gmp).wrap() - } - - fn mod_floor(&self, other: &Self) -> Self { - self.gmp.mod_floor(&other.gmp).wrap() - } - - fn gcd(&self, other: &Self) -> Self { - self.gmp.gcd(&other.gmp).wrap() - } - - fn lcm(&self, other: &Self) -> Self { - self.gmp.lcm(&other.gmp).wrap() - } - - fn divides(&self, other: &Self) -> bool { - self.gmp.divides(&other.gmp) - } - - fn is_multiple_of(&self, other: &Self) -> bool { - self.gmp.is_multiple_of(&other.gmp) - } - - fn is_even(&self) -> bool { - self.gmp.is_multiple_of(&Mpz::from(2)) - } - - fn is_odd(&self) -> bool { - !self.gmp.is_multiple_of(&Mpz::from(2)) - } - - fn div_rem(&self, other: &Self) -> (Self, Self) { - let n = self / other; - let m = self % other; - (n, m) - } -} - -impl Roots for BigInt { - fn nth_root(&self, n: u32) -> Self { - self.gmp.root(n).wrap() - } - - fn sqrt(&self) -> Self { - self.gmp.sqrt().wrap() - } -} - -impl fmt::Display for BigInt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.gmp.fmt(f) - } -} - -impl fmt::Debug for BigInt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.gmp.fmt(f) - } -} - -macro_rules! impl_try_from { - ($($primitive:ty),*$(,)?) => { - $( - impl TryFrom<&BigInt> for $primitive { - type Error = TryFromBigIntError; - - fn try_from(value: &BigInt) -> Result { - Option::<$primitive>::from(&value.gmp) - .ok_or(TryFromBigIntError { type_name: stringify!($primitive) }) - } - } - )* - }; -} - -impl_try_from! { u64, i64 } - -#[allow(deprecated)] -impl ConvertFrom for u64 { - fn _from(x: &BigInt) -> u64 { - let opt_x: Option = (&x.gmp).into(); - opt_x.unwrap() - } -} - -crate::__bigint_impl_ops! { - Add add, - Sub sub, - Mul mul, - Div div, - Rem rem, - BitAnd bitand, - BitXor bitxor, - Shl shl usize, - Shr shr usize, - - Add add u64 [swap], - Sub sub u64 [swap], - Mul mul u64 [swap], - Div div u64, - Rem rem u64, -} - -crate::__bigint_impl_assigns! { - AddAssign add_assign, - AddAssign add_assign u64, - BitAndAssign bitand_assign, - BitOrAssign bitor_assign, - BitXorAssign bitxor_assign, - DivAssign div_assign, - DivAssign div_assign u64, - MulAssign mul_assign, - MulAssign mul_assign u64, - RemAssign rem_assign, - RemAssign rem_assign u64, - ShlAssign shl_assign usize, - ShrAssign shr_assign usize, - SubAssign sub_assign, - SubAssign sub_assign u64, -} - -impl ops::Neg for BigInt { - type Output = BigInt; - fn neg(self) -> Self::Output { - self.gmp.neg().wrap() - } -} -impl ops::Neg for &BigInt { - type Output = BigInt; - fn neg(self) -> Self::Output { - (&self.gmp).neg().wrap() - } -} - -impl Zero for BigInt { - fn zero() -> Self { - Mpz::zero().wrap() - } - - fn is_zero(&self) -> bool { - self.gmp.is_zero() - } -} - -impl One for BigInt { - fn one() -> Self { - Mpz::one().wrap() - } - fn is_one(&self) -> bool { - self.gmp.is_one() - } -} - -impl ring_algorithm::RingNormalize for BigInt { - fn leading_unit(&self) -> Self { - match self.gmp.sign() { - Sign::Negative => -BigInt::one(), - _ => BigInt::one(), - } - } - - fn normalize_mut(&mut self) { - self.gmp = self.gmp.abs(); - } -} - -crate::__bigint_impl_from! { u32, i32, u64 } - -/// Internal helper trait. Creates short-hand for wrapping Mpz into BigInt. -trait Wrap { - fn wrap(self) -> BigInt; -} -impl Wrap for Mpz { - fn wrap(self) -> BigInt { - BigInt { gmp: self } - } -} - -/// Tests that ring_algorithm work as expected -#[cfg(test)] -mod ring_algorithm_test { - const PRIME: u32 = u32::MAX - 4; - - use super::*; - - proptest::proptest! { - #[test] - fn fuzz_inverse(n in 1..PRIME) { - test_inverse(BigInt::from(n)) - } - #[test] - fn fuzz_xgcd(a in 1u32.., b in 1u32..) { - test_xgcd(BigInt::from(a), BigInt::from(b)) - } - } - - fn test_inverse(n: BigInt) { - let prime = BigInt::from(PRIME); - let n_inv_expected = BigInt::mod_inv(&n, &prime).unwrap(); - let n_inv_actual = ring_algorithm::modulo_inverse(n, prime.clone()).unwrap(); - assert_eq!(n_inv_expected, n_inv_actual.modulus(&prime)); - } - - fn test_xgcd(a: BigInt, b: BigInt) { - let (s1, p1, q1) = BigInt::egcd(&a, &b); - let (s2, p2, q2) = ring_algorithm::normalized_extended_euclidian_algorithm(a, b); - assert_eq!((s1, p1, q1), (s2, p2, q2)); - } -} diff --git a/src/arithmetic/big_native.rs b/src/arithmetic/big_native.rs deleted file mode 100644 index 8ccfd1d8..00000000 --- a/src/arithmetic/big_native.rs +++ /dev/null @@ -1,420 +0,0 @@ -use std::convert::{TryFrom, TryInto}; -use std::{fmt, ops}; - -use num_traits::Signed; -use serde::{Deserialize, Serialize}; - -use super::errors::*; -use super::traits::*; - -use num_bigint::BigInt as BN; -use num_bigint::Sign; - -mod primes; - -/// Big integer -/// -/// Wraps underlying BigInt implementation (either GMP bindings or num-bigint), exposes only -/// very limited API that allows easily switching between implementations. -/// -/// Set of traits implemented on BigInt remains the same regardless of underlying implementation. -#[derive(PartialOrd, PartialEq, Ord, Eq, Clone, Serialize, Deserialize)] -#[serde(transparent)] -pub struct BigInt { - num: BN, -} - -impl BigInt { - fn inner_ref(&self) -> &BN { - &self.num - } - fn inner_mut(&mut self) -> &mut BN { - &mut self.num - } - fn into_inner(self) -> BN { - self.num - } -} - -#[allow(deprecated)] -impl ZeroizeBN for BigInt { - fn zeroize_bn(&mut self) { - zeroize::Zeroize::zeroize(self) - } -} - -impl zeroize::Zeroize for BigInt { - fn zeroize(&mut self) { - use std::{ptr, sync::atomic}; - unsafe { ptr::write_volatile(&mut self.num, Zero::zero()) }; - atomic::fence(atomic::Ordering::SeqCst); - atomic::compiler_fence(atomic::Ordering::SeqCst); - } -} - -impl Converter for BigInt { - fn to_bytes(&self) -> Vec { - let (_sign, bytes) = self.num.to_bytes_be(); - bytes - } - - fn from_bytes(bytes: &[u8]) -> Self { - BN::from_bytes_be(Sign::Plus, bytes).wrap() - } - - fn to_hex(&self) -> String { - self.num.to_str_radix(16) - } - - fn from_hex(n: &str) -> Result { - BN::parse_bytes(n.as_bytes(), 16) - .map(Wrap::wrap) - .ok_or(ParseBigIntError { - reason: ParseErrorReason::NumBigint, - radix: 16, - }) - } - - fn to_str_radix(&self, radix: u8) -> String { - self.num.to_str_radix(radix.into()) - } - - fn from_str_radix(str: &str, radix: u8) -> Result { - BN::parse_bytes(str.as_bytes(), radix.into()) - .map(Wrap::wrap) - .ok_or(ParseBigIntError { - reason: ParseErrorReason::NumBigint, - radix: radix.into(), - }) - } -} - -impl num_traits::Num for BigInt { - type FromStrRadixErr = ParseBigIntError; - - fn from_str_radix(str: &str, radix: u32) -> Result { - ::from_str_radix(str, radix.try_into().unwrap()) - } -} - -crate::__bigint_impl_from! { u32, i32, u64 } - -impl BasicOps for BigInt { - fn pow(&self, exponent: u32) -> Self { - self.num.pow(exponent).wrap() - } - - fn mul(&self, other: &Self) -> Self { - self * other - } - - fn sub(&self, other: &Self) -> Self { - self - other - } - - fn add(&self, other: &Self) -> Self { - self + other - } - - fn abs(&self) -> Self { - self.num.abs().wrap() - } -} - -impl Primes for BigInt { - fn next_prime(&self) -> BigInt { - if self.num.sign() != Sign::Plus { - return BigInt::from(2); - } - let uint = primes::next_prime(self.num.magnitude()); - BN::from_biguint(Sign::Plus, uint).wrap() - } - - fn is_probable_prime(&self, n: u32) -> bool { - if self.num.sign() != Sign::Plus { - false - } else { - primes::probably_prime(self.num.magnitude(), n as usize) - } - } -} - -impl Modulo for BigInt { - fn mod_pow(base: &Self, exponent: &Self, modulus: &Self) -> Self { - base.num.modpow(&exponent.num, &modulus.num).wrap() - } - - fn mod_mul(a: &Self, b: &Self, modulus: &Self) -> Self { - (a.num.mod_floor(&modulus.num) * b.num.mod_floor(&modulus.num)) - .mod_floor(&modulus.num) - .wrap() - } - - fn mod_sub(a: &Self, b: &Self, modulus: &Self) -> Self { - let a_m = a.num.mod_floor(&modulus.num); - let b_m = b.num.mod_floor(&modulus.num); - - let sub_op = a_m - b_m + &modulus.num; - sub_op.mod_floor(&modulus.num).wrap() - } - - fn mod_add(a: &Self, b: &Self, modulus: &Self) -> Self { - (a.num.mod_floor(&modulus.num) + b.num.mod_floor(&modulus.num)) - .mod_floor(&modulus.num) - .wrap() - } - - fn mod_inv(a: &Self, modulus: &Self) -> Option { - ring_algorithm::modulo_inverse(a.clone(), modulus.clone()).map(|inv| inv.modulus(modulus)) - } - - fn modulus(&self, modulus: &Self) -> Self { - let n = self % modulus; - if n.num.sign() == Sign::Minus { - modulus + n - } else { - n - } - } -} - -impl BitManipulation for BigInt { - fn set_bit(&mut self, bit: usize, bit_val: bool) { - let mask = BigInt::one() << bit; - if bit_val { - *self |= mask; - } else if self.test_bit(bit) { - *self ^= mask; - } - } - - fn test_bit(&self, bit: usize) -> bool { - let mask = BigInt::one() << bit; - !(self & mask).is_zero() - } - - fn bit_length(&self) -> usize { - self.num.bits() as usize - } -} - -impl NumberTests for BigInt { - fn is_zero(n: &Self) -> bool { - matches!(n.num.sign(), Sign::NoSign) - } - - fn is_negative(n: &Self) -> bool { - matches!(n.num.sign(), Sign::Minus) - } -} - -impl EGCD for BigInt { - fn egcd(a: &Self, b: &Self) -> (Self, Self, Self) { - ring_algorithm::normalized_extended_euclidian_algorithm(a.clone(), b.clone()) - } -} - -impl Integer for BigInt { - fn div_floor(&self, other: &Self) -> Self { - self.num.div_floor(&other.num).wrap() - } - - fn mod_floor(&self, other: &Self) -> Self { - self.num.mod_floor(&other.num).wrap() - } - - fn div_ceil(&self, other: &Self) -> Self { - self.num.div_ceil(&other.num).wrap() - } - - fn gcd(&self, other: &Self) -> Self { - self.num.gcd(&other.num).wrap() - } - - fn lcm(&self, other: &Self) -> Self { - self.num.lcm(&other.num).wrap() - } - - fn gcd_lcm(&self, other: &Self) -> (Self, Self) { - let (n, m) = self.num.gcd_lcm(&other.num); - (n.wrap(), m.wrap()) - } - - fn divides(&self, other: &Self) -> bool { - self.num.divides(&other.num) - } - - fn is_multiple_of(&self, other: &Self) -> bool { - self.num.is_multiple_of(&other.num) - } - - fn is_even(&self) -> bool { - self.num.is_even() - } - - fn is_odd(&self) -> bool { - self.num.is_odd() - } - - fn div_rem(&self, other: &Self) -> (Self, Self) { - let (n, m) = self.num.div_rem(&other.num); - (n.wrap(), m.wrap()) - } - - fn div_mod_floor(&self, other: &Self) -> (Self, Self) { - let (n, m) = self.num.div_mod_floor(&other.num); - (n.wrap(), m.wrap()) - } - - fn next_multiple_of(&self, other: &Self) -> Self - where - Self: Clone, - { - self.num.next_multiple_of(&other.num).wrap() - } - - fn prev_multiple_of(&self, other: &Self) -> Self - where - Self: Clone, - { - self.num.prev_multiple_of(&other.num).wrap() - } -} - -impl Roots for BigInt { - fn nth_root(&self, n: u32) -> Self { - self.num.nth_root(n).wrap() - } - - fn sqrt(&self) -> Self { - self.num.sqrt().wrap() - } - - fn cbrt(&self) -> Self { - self.num.cbrt().wrap() - } -} - -impl fmt::Display for BigInt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.num.fmt(f) - } -} - -impl fmt::Debug for BigInt { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.num.fmt(f) - } -} - -crate::__bigint_impl_ops! { - Add add, - Sub sub, - Mul mul, - Div div, - Rem rem, - BitAnd bitand, - BitXor bitxor, - Shl shl usize, - Shr shr usize, - - Add add u64 [swap], - Sub sub u64 [swap], - Mul mul u64 [swap], - Div div u64, - Rem rem u64, -} - -crate::__bigint_impl_assigns! { - AddAssign add_assign, - AddAssign add_assign u64, - BitAndAssign bitand_assign, - BitOrAssign bitor_assign, - BitXorAssign bitxor_assign, - DivAssign div_assign, - DivAssign div_assign u64, - MulAssign mul_assign, - MulAssign mul_assign u64, - RemAssign rem_assign, - RemAssign rem_assign u64, - ShlAssign shl_assign usize, - ShrAssign shr_assign usize, - SubAssign sub_assign, - SubAssign sub_assign u64, -} - -impl ops::Neg for BigInt { - type Output = BigInt; - fn neg(self) -> Self::Output { - self.num.neg().wrap() - } -} -impl ops::Neg for &BigInt { - type Output = BigInt; - fn neg(self) -> Self::Output { - (&self.num).neg().wrap() - } -} - -impl num_traits::Zero for BigInt { - fn zero() -> Self { - BN::zero().wrap() - } - fn is_zero(&self) -> bool { - matches!(self.num.sign(), Sign::NoSign) - } -} - -impl num_traits::One for BigInt { - fn one() -> Self { - BN::one().wrap() - } -} - -impl ring_algorithm::RingNormalize for BigInt { - fn leading_unit(&self) -> Self { - match self.num.sign() { - Sign::Minus => -BigInt::one(), - _ => BigInt::one(), - } - } - - fn normalize_mut(&mut self) { - self.num = self.num.abs(); - } -} - -macro_rules! impl_try_from { - ($($primitive:ty),*$(,)?) => { - $( - impl TryFrom<&BigInt> for $primitive { - type Error = TryFromBigIntError; - - fn try_from(value: &BigInt) -> Result { - TryFrom::<&BN>::try_from(&value.num) - .map_err(|_| TryFromBigIntError { type_name: stringify!($primitive) }) - } - } - )* - }; -} - -impl_try_from! { u64, i64 } - -#[allow(deprecated)] -impl ConvertFrom for u64 { - fn _from(x: &BigInt) -> u64 { - let opt_x: u64 = (&x.num).try_into().unwrap(); - opt_x - } -} - -/// Internal helper trait. Creates short-hand for wrapping Mpz into BigInt. -trait Wrap { - fn wrap(self) -> BigInt; -} -impl Wrap for BN { - fn wrap(self) -> BigInt { - BigInt { num: self } - } -} diff --git a/src/arithmetic/errors.rs b/src/arithmetic/errors.rs index d26e5244..425c5f44 100644 --- a/src/arithmetic/errors.rs +++ b/src/arithmetic/errors.rs @@ -4,13 +4,14 @@ use std::{error, fmt}; #[derive(Debug)] pub struct ParseBigIntError { pub(super) reason: ParseErrorReason, - pub(super) radix: u32, + pub(super) radix: u8, } #[derive(Debug)] +#[non_exhaustive] pub enum ParseErrorReason { - #[cfg(feature = "rust-gmp-kzen")] - Gmp(gmp::mpz::ParseMpzError), + #[cfg(feature = "rug")] + Gmp(rug::integer::ParseIntegerError), #[cfg(feature = "num-bigint")] NumBigint, } @@ -18,7 +19,7 @@ pub enum ParseErrorReason { impl fmt::Display for ParseBigIntError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.reason { - #[cfg(feature = "rust-gmp-kzen")] + #[cfg(feature = "rug")] ParseErrorReason::Gmp(reason) => write!(f, "{}", reason), #[cfg(feature = "num-bigint")] ParseErrorReason::NumBigint => { @@ -31,7 +32,7 @@ impl fmt::Display for ParseBigIntError { impl error::Error for ParseBigIntError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.reason { - #[cfg(feature = "rust-gmp-kzen")] + #[cfg(feature = "rug")] ParseErrorReason::Gmp(reason) => Some(reason), #[cfg(feature = "num-bigint")] ParseErrorReason::NumBigint => None, diff --git a/src/arithmetic/gmp.rs b/src/arithmetic/gmp.rs new file mode 100644 index 00000000..025467e7 --- /dev/null +++ b/src/arithmetic/gmp.rs @@ -0,0 +1,144 @@ +use std::cmp::Ordering; +use std::convert::TryFrom; +use std::sync::atomic; + +use rug::Assign; +pub use rug::Integer as BigInt; +use rug::integer::Order; +use rug::ops::RemRounding; + +use crate::arithmetic::traits::{self, BigInt as _}; + +use super::errors::*; + +/// Big integer +/// +/// Wraps underlying BigInt implementation (either GMP bindings or num-bigint), exposes only +/// very limited API that allows easily switching between implementations. +/// +/// Set of traits implemented on BigInt remains the same regardless of underlying implementation. + +impl traits::BigInt for BigInt { + fn zero() -> Self { + Self::new() + } + + fn is_zero(&self) -> bool { + self.cmp0() == Ordering::Equal + } + + fn set_zero(&mut self) { + self.assign(0); + } + + fn one() -> Self { + Self::from(1u8) + } + + fn set_one(&mut self) { + self.assign(1); + } + + fn is_negative(&self) -> bool { + self.cmp0() == Ordering::Less + } + + fn set_bit(&mut self, bit: usize, bit_val: bool) { + self.set_bit( + u32::try_from(bit).expect("There shouldn't be more than 2^32-1 bits"), + bit_val, + ); + } + + fn test_bit(&self, bit: usize) -> bool { + self.get_bit(u32::try_from(bit).expect("There shouldn't be more than 2^32-1 bits")) + } + + fn bit_length(&self) -> usize { + usize::try_from(self.significant_bits()).expect("usize should always be bigger than u32") + } + + fn to_bytes(&self) -> Vec { + self.to_digits(Order::MsfBe) + } + + fn from_bytes(bytes: &[u8]) -> Self { + Self::from_digits(bytes, Order::MsfBe) + } + + fn to_str_radix(&self, radix: u8) -> String { + self.to_string_radix(i32::from(radix)) + } + + fn from_str_radix(s: &str, radix: u8) -> Result { + Self::from_str_radix(s, i32::from(radix)).map_err(|e| ParseBigIntError { + reason: ParseErrorReason::Gmp(e), + radix, + }) + } + + fn zeroize(&mut self) { + let mpz = unsafe { self.as_raw_mut().read() }; + let mut ptr = mpz.d.as_ptr(); + for _ in 0..mpz.alloc { + unsafe { + // SAFETY: The pointer is properly aligned and valid + // because we got it from the gmp allocation which allocates limbs + // The pointer is valid for writes because we assume `rug` handles it correctly. + ptr.write_volatile(0); + // SAFETY: The starting pointer is in bounds, + // and the last pointer will point at a single byte past the last element. + ptr = ptr.add(1) + } + } + atomic::fence(atomic::Ordering::SeqCst); + atomic::compiler_fence(atomic::Ordering::SeqCst); + } +} + +impl traits::NumberTheoreticOps for BigInt { + fn mod_pow(&self, exponent: &Self, modulo: &Self) -> Self { + Self::from( + self.pow_mod_ref(exponent, modulo) + .expect("exponent must be non-negative"), + ) + } + + fn mod_mul(&self, b: &Self, modulus: &Self) -> Self { + BigInt::from(self * b).rem_floor(modulus) + } + + fn mod_sub(&self, b: &Self, modulus: &Self) -> Self { + BigInt::from(self - b).rem_floor(modulus) + } + + fn mod_add(&self, b: &Self, modulus: &Self) -> Self { + BigInt::from(self + b).rem_floor(modulus) + } + + fn mod_inv(&self, modulo: &Self) -> Option { + self.clone().invert(modulo).ok() + } + + fn modulus(&self, modulus: &Self) -> Self { + BigInt::from(self.rem_floor(modulus)) + } + + fn egcd(&self, b: &Self) -> (Self, Self, Self) { + let (s, p, q) = self.clone().gcd_cofactors(b.clone(), Self::zero()); + (s, p, q) + } + + fn gcd(&self, m: &Self) -> Self { + self.clone().gcd(&m) + } + + fn next_prime(&self) -> Self { + BigInt::next_prime(self.clone()) + } + + fn is_probable_prime(&self, n: u32) -> bool { + use rug::integer::IsPrime; + self.is_probably_prime(n) != IsPrime::No + } +} diff --git a/src/arithmetic/macros.rs b/src/arithmetic/macros.rs index 2f2f2a24..2f504ce0 100644 --- a/src/arithmetic/macros.rs +++ b/src/arithmetic/macros.rs @@ -1,89 +1,129 @@ -#[doc(hidden)] -#[macro_export] -macro_rules! __bigint_impl_from { - ($($type:ty),*$(,)?) => { - $( - impl From<$type> for BigInt { - fn from(x: $type) -> Self { - BN::from(x).wrap() - } - } - )* - }; -} - #[doc(hidden)] #[macro_export] macro_rules! __bigint_impl_ops { - () => {}; - ($op: ident $func:ident, $($rest:tt)*) => { + ($($op: ident $func:ident),+$(,)?) => { + $( impl ops::$op for &BigInt { type Output = BigInt; fn $func(self, rhs: Self) -> Self::Output { - self.inner_ref().$func(rhs.inner_ref()).wrap() + BigInt((&self.0).$func(&rhs.0)) } } impl ops::$op for BigInt { type Output = BigInt; fn $func(self, rhs: Self) -> Self::Output { - self.into_inner().$func(rhs.into_inner()).wrap() + BigInt(self.0.$func(rhs.0)) } } impl ops::$op for &BigInt { type Output = BigInt; fn $func(self, rhs: BigInt) -> Self::Output { - self.inner_ref().$func(rhs.into_inner()).wrap() + BigInt((&self.0).$func(rhs.0)) } } impl ops::$op<&BigInt> for BigInt { type Output = BigInt; fn $func(self, rhs: &BigInt) -> Self::Output { - self.into_inner().$func(rhs.inner_ref()).wrap() + BigInt(self.0.$func(&rhs.0)) } } - $crate::__bigint_impl_ops!{ $($rest)* } + )+ }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __bigint_impl_primitives_ops { + () => {}; ($op: ident $func:ident $primitive:ty, $($rest:tt)*) => { impl ops::$op<$primitive> for BigInt { type Output = BigInt; fn $func(self, rhs: $primitive) -> Self::Output { - self.into_inner().$func(rhs).wrap() + BigInt(self.0.$func(rhs)) } } impl ops::$op<$primitive> for &BigInt { type Output = BigInt; fn $func(self, rhs: $primitive) -> Self::Output { - (&self.inner_ref()).$func(rhs).wrap() + BigInt((&self.0).$func(rhs)) } } - $crate::__bigint_impl_ops!{ $($rest)* } + $crate::__bigint_impl_primitives_ops!($($rest)*); }; - ($op: ident $func:ident $primitive:ty [swap], $($rest:tt)*) => { - impl ops::$op<$primitive> for BigInt { + (swap => $op: ident $func:ident $primitive:ty, $($rest:tt)*) => { + impl ops::$op<$primitive> for BigInt { type Output = BigInt; fn $func(self, rhs: $primitive) -> Self::Output { - self.into_inner().$func(rhs).wrap() + BigInt(self.0.$func(rhs)) } } impl ops::$op<$primitive> for &BigInt { type Output = BigInt; fn $func(self, rhs: $primitive) -> Self::Output { - (&self.inner_ref()).$func(rhs).wrap() + BigInt((&self.0).$func(rhs)) + } + } + impl ops::$op<&$primitive> for BigInt { + type Output = BigInt; + fn $func(self, rhs: &$primitive) -> Self::Output { + BigInt(self.0.$func(rhs)) + } + } + impl ops::$op<&$primitive> for &BigInt { + type Output = BigInt; + fn $func(self, rhs: &$primitive) -> Self::Output { + BigInt((&self.0).$func(rhs)) } } impl ops::$op for $primitive { type Output = BigInt; fn $func(self, rhs: BigInt) -> Self::Output { - self.$func(rhs.into_inner()).wrap() + BigInt(self.$func(rhs.0)) } } impl ops::$op<&BigInt> for $primitive { type Output = BigInt; fn $func(self, rhs: &BigInt) -> Self::Output { - self.$func(rhs.inner_ref()).wrap() + BigInt(self.$func(&rhs.0)) } } - $crate::__bigint_impl_ops!{ $($rest)* } + $crate::__bigint_impl_primitives_ops!($($rest)*); + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __bigint_impl_all_primitives_ops { + () => {}; + ($op: ident $func:ident, $($rest:tt)*) => { + $crate::__bigint_impl_primitives_ops!( + $op $func u8, + $op $func i8, + $op $func u16, + $op $func i16, + $op $func u32, + $op $func i32, + $op $func u64, + $op $func i64, + $op $func u128, + $op $func i128, + ); + $crate::__bigint_impl_all_primitives_ops!{ $($rest)* } + }; + (swap => $op: ident $func:ident, $($rest:tt)*) => { + $crate::__bigint_impl_primitives_ops!( + swap => $op $func u8, + swap => $op $func i8, + swap => $op $func u16, + swap => $op $func i16, + swap => $op $func u32, + swap => $op $func i32, + swap => $op $func u64, + swap => $op $func i64, + swap => $op $func u128, + swap => $op $func i128, + ); + $crate::__bigint_impl_all_primitives_ops!{ $($rest)* } }; } @@ -91,15 +131,15 @@ macro_rules! __bigint_impl_ops { #[macro_export] macro_rules! __bigint_impl_assigns { () => {}; - ($trait:ident $fn:ident, $($rest:tt)*) => { + ($trait: ident $fn:ident, $($rest:tt)*) => { impl ops::$trait for BigInt { fn $fn(&mut self, rhs: BigInt) { - self.inner_mut().$fn(rhs.into_inner()) + self.0.$fn(rhs.0) } } impl ops::$trait<&BigInt> for BigInt { fn $fn(&mut self, rhs: &BigInt) { - self.inner_mut().$fn(rhs.inner_ref()) + self.0.$fn(&rhs.0) } } $crate::__bigint_impl_assigns!{ $($rest)* } @@ -107,9 +147,62 @@ macro_rules! __bigint_impl_assigns { ($trait:ident $fn:ident $primitive:ident, $($rest:tt)*) => { impl ops::$trait<$primitive> for BigInt { fn $fn(&mut self, rhs: $primitive) { - self.inner_mut().$fn(rhs) + self.0.$fn(rhs) } } $crate::__bigint_impl_assigns!{ $($rest)* } }; } + +#[doc(hidden)] +#[macro_export] +macro_rules! __bigint_impl_fmt { + ($(impl $trait:ident for $type:ty),+$(,)?) => { + $( + impl core::fmt::$trait for $type { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result { + core::fmt::$trait::fmt(&self.0, f) // delegate to inner + } + } + )+ + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __bigint_impl_from { + ($($scalar:ty => $trait:ident => $func:ident),+$(,)?) => { + $( + impl $trait<$scalar> for BigInt { + fn $func(input: $scalar) -> Self { + BigInt($trait::$func(input)) + } + } + impl $trait<&$scalar> for BigInt { + fn $func(input: &$scalar) -> Self { + BigInt($trait::$func(*input)) + } + } + )+ + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __bigint_impl_cmp { + () => {}; + (impl $rhs:ident with $transform:path, $($rest:tt)*) => { + impl PartialOrd<$rhs> for BigInt { + fn partial_cmp(&self, other: &$rhs) -> Option { + Some(self.cmp(&$transform(*other))) + } + } + + impl PartialEq<$rhs> for BigInt { + fn eq(&self, other: &$rhs) -> bool { + *self == $transform(*other) + } + } + $crate::__bigint_impl_cmp!{ $($rest)* } + }; +} diff --git a/src/arithmetic/mod.rs b/src/arithmetic/mod.rs index dbda76a7..a8b615c4 100644 --- a/src/arithmetic/mod.rs +++ b/src/arithmetic/mod.rs @@ -16,23 +16,18 @@ mod errors; mod macros; -mod samplable; pub mod traits; -#[cfg(not(any(feature = "rust-gmp-kzen", feature = "num-bigint")))] +pub use traits::{BigInt, NumberTheoreticOps}; + +#[cfg(not(any(feature = "rug", feature = "num-bigint")))] compile_error!("You need to choose which bigint implementation to use. See crate features."); -#[cfg(all(feature = "rust-gmp-kzen", feature = "num-bigint"))] -compile_error!("You can choose only one bigint implementation. See crate features."); -#[cfg(feature = "rust-gmp-kzen")] -mod big_gmp; -#[cfg(feature = "rust-gmp-kzen")] -pub use big_gmp::BigInt; +#[cfg(feature = "rug")] +pub mod gmp; #[cfg(feature = "num-bigint")] -mod big_native; -#[cfg(feature = "num-bigint")] -pub use big_native::BigInt; +pub mod native; pub use errors::{ParseBigIntError, TryFromBigIntError}; pub use traits::*; diff --git a/src/arithmetic/native.rs b/src/arithmetic/native.rs new file mode 100644 index 00000000..9a5eb1d3 --- /dev/null +++ b/src/arithmetic/native.rs @@ -0,0 +1,253 @@ +use core::convert::From; +use std::{cmp, ptr}; +use std::convert::TryFrom; +use std::ops; + +use num_bigint::BigInt as BN; +use num_bigint::Sign; +use num_integer::Integer; +use num_traits::{One, Zero}; +use zeroize::Zeroize; + +use super::errors::*; +use super::traits::{self, BigInt as _}; + +mod primes; + +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone)] +pub struct BigInt(num_bigint::BigInt); +/// Big integer +/// +/// Wraps underlying BigInt implementation (either GMP bindings or num-bigint), exposes only +/// very limited API that allows easily switching between implementations. +/// +/// Set of traits implemented on BigInt remains the same regardless of underlying implementation. +impl traits::BigInt for BigInt { + fn zero() -> Self { + Self(BN::zero()) + } + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + fn set_zero(&mut self) { + self.0.set_zero() + } + + fn one() -> Self { + Self(BN::one()) + } + + fn is_one(&self) -> bool { + self.0.is_one() + } + + fn set_one(&mut self) { + self.0.set_one() + } + + fn is_negative(&self) -> bool { + self.0.sign() == Sign::Minus + } + + fn set_bit(&mut self, bit: usize, bit_val: bool) { + self.0 + .set_bit(u64::try_from(bit).expect("u64 >= usize"), bit_val); + } + fn test_bit(&self, bit: usize) -> bool { + self.0.bit(u64::try_from(bit).expect("u64 >= usize")) + } + + fn bit_length(&self) -> usize { + usize::try_from(self.0.bits()).expect("there shouldn't be more than usize bits") + } + + fn to_bytes(&self) -> Vec { + let (_, bytes) = self.0.to_bytes_be(); + bytes + } + + fn from_bytes(bytes: &[u8]) -> Self { + Self(BN::from_bytes_be(Sign::Plus, bytes)) + } + + fn to_str_radix(&self, radix: u8) -> String { + self.0.to_str_radix(radix.into()) + } + fn from_str_radix(str: &str, radix: u8) -> Result { + BN::parse_bytes(str.as_bytes(), radix.into()) + .map(Self) + .ok_or(ParseBigIntError { + reason: ParseErrorReason::NumBigint, + radix, + }) + } + fn zeroize(&mut self) { + use core::sync::atomic; + // Copy the inner so we can read the data inside + let original = unsafe { ptr::read(self) }; + // Replace self with a zeroed integer. + unsafe { ptr::write_volatile(self, Self::zero()) }; + let (mut sign, uint) = original.0.into_parts(); + // Zero out the temp sign in case it's a secret somehow + unsafe { ptr::write_volatile(&mut sign, Sign::NoSign) }; + // zero out the bigint's data itself. + // This is semi-UB because it's a repr(Rust) type, but because it's a single field we can assume it matches the wrapper. + let mut data: Vec = unsafe { core::mem::transmute(uint) }; + atomic::compiler_fence(atomic::Ordering::SeqCst); + data.zeroize(); + } +} + +impl traits::NumberTheoreticOps for BigInt { + fn mod_pow(&self, exponent: &Self, modulo: &Self) -> Self { + Self(self.0.modpow(&exponent.0, &modulo.0)) + } + + fn mod_mul(&self, b: &Self, modulus: &Self) -> Self { + Self((&self.0 * &b.0).mod_floor(&modulus.0)) + } + + fn mod_sub(&self, b: &Self, modulus: &Self) -> Self { + Self((&self.0 - &b.0).mod_floor(&modulus.0)) + } + + fn mod_add(&self, b: &Self, modulus: &Self) -> Self { + Self((&self.0 + &b.0).mod_floor(&modulus.0)) + } + + fn mod_inv(&self, modulo: &Self) -> Option { + let (gcd, x, _) = self.egcd(modulo); + // if the gcd of (a,m) is one then the x Bézout's coefficient is the mod inverse + // a*x + m*y = gcd + // a*x + m*y = 1 + // a*x = 1 (mod m) + // x = a^-1 (mod m) + if gcd.is_one() { + Some(x) + } else { + None + } + } + + fn modulus(&self, modulus: &Self) -> Self { + Self(self.0.mod_floor(&modulus.0)) + } + + fn egcd(&self, b: &Self) -> (Self, Self, Self) { + let extended = self.0.extended_gcd(&b.0); + (Self(extended.gcd), Self(extended.x), Self(extended.y)) + } + + fn gcd(&self, m: &Self) -> Self { + Self(self.0.gcd(&m.0)) + } + + fn next_prime(&self) -> Self { + if self.0.sign() != Sign::Plus { + return Self::from(2); + } + let uint = primes::next_prime(self.0.magnitude()); + Self(BN::from_biguint(Sign::Plus, uint)) + } + + fn is_probable_prime(&self, n: u32) -> bool { + if self.0.sign() != Sign::Plus { + false + } else { + primes::probably_prime(self.0.magnitude(), n as usize) + } + } +} + +crate::__bigint_impl_ops! { + Add add, + Sub sub, + Mul mul, + Div div, + Rem rem, + BitAnd bitand, + BitXor bitxor, +} + +crate::__bigint_impl_primitives_ops! { + Shl shl u32, + Shl shl i32, + Shr shr u32, + Shr shr i32, +} + +crate::__bigint_impl_all_primitives_ops! { + Div div, + Rem rem, + swap => Add add, + swap => Sub sub, + swap => Mul mul, +} + +crate::__bigint_impl_fmt! { + impl Binary for BigInt, + impl Display for BigInt, + impl LowerHex for BigInt, + impl Octal for BigInt, + impl UpperHex for BigInt, +} + +crate::__bigint_impl_from! { + i8 => From => from, + u8 => From => from, + i16 => From => from, + u16 => From => from, + i32 => From => from, + u32 => From => from, + i64 => From => from, + u64 => From => from, + i128 => From => from, + u128 => From => from, + isize => From => from, + usize => From => from +} + +crate::__bigint_impl_assigns! { + AddAssign add_assign, + AddAssign add_assign u64, + AddAssign add_assign u32, + AddAssign add_assign i32, + AddAssign add_assign i64, + BitAndAssign bitand_assign, + BitOrAssign bitor_assign, + BitXorAssign bitxor_assign, + DivAssign div_assign, + DivAssign div_assign u64, + DivAssign div_assign u32, + DivAssign div_assign i32, + DivAssign div_assign i64, + MulAssign mul_assign, + MulAssign mul_assign u64, + MulAssign mul_assign u32, + MulAssign mul_assign i32, + MulAssign mul_assign i64, + RemAssign rem_assign, + RemAssign rem_assign u64, + RemAssign rem_assign u32, + RemAssign rem_assign i32, + RemAssign rem_assign i64, + ShlAssign shl_assign usize, + ShlAssign shl_assign u32, + ShlAssign shl_assign i32, + ShrAssign shr_assign usize, + ShrAssign shr_assign u32, + ShrAssign shr_assign i32, + SubAssign sub_assign, + SubAssign sub_assign u64, + SubAssign sub_assign u32, + SubAssign sub_assign i64, + SubAssign sub_assign i32, +} + +crate::__bigint_impl_cmp! { + impl i32 with Self::from, + impl i64 with Self::from, + impl u32 with Self::from, + impl u64 with Self::from, +} diff --git a/src/arithmetic/big_native/primes.rs b/src/arithmetic/native/primes.rs similarity index 100% rename from src/arithmetic/big_native/primes.rs rename to src/arithmetic/native/primes.rs diff --git a/src/arithmetic/samplable.rs b/src/arithmetic/samplable.rs deleted file mode 100644 index 1b069b3a..00000000 --- a/src/arithmetic/samplable.rs +++ /dev/null @@ -1,56 +0,0 @@ -use rand::{rngs::OsRng, RngCore}; - -use super::traits::{BitManipulation, Converter, Samplable, Zero}; -use super::BigInt; - -impl Samplable for BigInt { - fn sample_below(upper: &Self) -> Self { - assert!(*upper > Self::zero()); - - let bits = upper.bit_length(); - loop { - let n = Self::sample(bits); - if n < *upper { - return n; - } - } - } - - fn sample_range(lower: &Self, upper: &Self) -> Self { - assert!(upper > lower); - lower + Self::sample_below(&(upper - lower)) - } - - fn strict_sample_range(lower: &Self, upper: &Self) -> Self { - assert!(upper > lower); - loop { - let n = lower + Self::sample_below(&(upper - lower)); - if n > *lower && n < *upper { - return n; - } - } - } - - fn sample(bit_size: usize) -> Self { - if bit_size == 0 { - return BigInt::zero(); - } - let mut rng = OsRng::new().unwrap(); - let bytes = (bit_size - 1) / 8 + 1; - let mut buf: Vec = vec![0; bytes]; - rng.fill_bytes(&mut buf); - BigInt::from_bytes(&*buf) >> (bytes * 8 - bit_size) - } - - fn strict_sample(bit_size: usize) -> Self { - if bit_size == 0 { - return BigInt::zero(); - } - loop { - let n = Self::sample(bit_size); - if n.bit_length() == bit_size { - return n; - } - } - } -} diff --git a/src/arithmetic/traits.rs b/src/arithmetic/traits.rs index 544bc1c6..b548e71c 100644 --- a/src/arithmetic/traits.rs +++ b/src/arithmetic/traits.rs @@ -1,50 +1,241 @@ -/* - Cryptography utilities +use std::convert::TryFrom; +use std::fmt::{Debug, LowerHex, UpperHex}; +use std::hash::Hash; +use std::ops::{ + Add, AddAssign, BitAnd, BitOrAssign, BitXorAssign, Mul, MulAssign, Shl, ShlAssign, + Shr, ShrAssign, Sub, SubAssign, +}; - Copyright 2018 by Kzen Networks +use rand::RngCore; - This file is part of Cryptography utilities library - (https://github.com/KZen-networks/cryptography-utils) - - Cryptography utilities is free software: you can redistribute - it and/or modify it under the terms of the GNU General Public - License as published by the Free Software Foundation, either - version 3 of the License, or (at your option) any later version. +use super::errors::ParseBigIntError; - @license GPL-3.0+ -*/ +pub trait BigInt: + // Integer + // + Roots + Sized + + PartialOrd + + PartialEq + + Ord + + Eq + + Hash + + Clone + + LowerHex + + UpperHex + + Debug + + Add + + Sub + + Mul + + Add + + Add + + Add + + Add + + AddAssign + + AddAssign + + AddAssign + + AddAssign + + Sub + + Sub + + Sub + + Sub + + SubAssign + + SubAssign + + SubAssign + + SubAssign + + Mul + + Mul + + Mul + + Mul + + MulAssign + + MulAssign + + MulAssign + + MulAssign + + Shr + + Shr + + ShrAssign + + ShrAssign + + Shl + + Shl + + ShlAssign + + ShlAssign + + BitOrAssign + + BitXorAssign + + BitAnd + + From + + From + + From + + From + + PartialOrd + + PartialOrd + + PartialOrd + + PartialOrd + + PartialEq + + PartialEq + + PartialEq + + PartialEq + + NumberTheoreticOps +where + for<'a> Self: Add<&'a Self, Output=Self>, + for<'a> Self: AddAssign<&'a Self>, + for<'a> Self: Sub<&'a Self, Output=Self>, + for<'a> Self: SubAssign<&'a Self>, + for<'a> Self: Mul<&'a Self, Output=Self>, + for<'a> Self: MulAssign<&'a Self>, + for<'a> Self: BitAnd<&'a Self, Output=Self>, +{ -use super::errors::ParseBigIntError; + /// Returns a new instance of `BigInt` with value 0. + fn zero() -> Self; + /// Returns `true` if `n` is zero + /// + /// Alternatively, [std::cmp::PartialEq] method can be used to compare with 0. + fn is_zero(&self) -> bool { + *self != 0 + } + /// Sets the value to 0. + fn set_zero(&mut self) { + *self = Self::zero(); + } + /// Returns a new instance of `BigInt` with value 1. + fn one() -> Self; + /// Returns `true` if `n` is 1 + /// + /// Alternatively, [std::cmp::PartialEq] method can be used to compare with 1. + fn is_one(&self) -> bool { + *self != 1 + } + /// Sets the value to 1. + fn set_one(&mut self) { + *self = Self::one(); + } + /// Returns `true` if `n` is negative + /// + /// Alternatively, [BasicOps::sign] method can be used to check sign of the number. + fn is_negative(&self) -> bool { + *self < 0i32 + } + /// Generates random number within `[0; upper)` range + /// + /// ## Panics + /// Panics if `upper <= 0` + fn sample_below(upper: &Self) -> Self { + assert!(*upper > Self::zero()); -/// Reuse common traits from [num_integer] crate -pub use num_integer::{Integer, Roots}; -/// Reuse common traits from [num_traits] crate -pub use num_traits::{One, Zero}; + let bits = upper.bit_length(); + loop { + let n = Self::sample(bits); + if n < *upper { + return n; + } + } + } + /// Generates random number within `[lower; upper)` range + /// + /// ## Panics + /// Panics if `upper <= lower` + fn sample_range(lower: &Self, upper: &Self) -> Self { + assert!(upper > lower); + Self::sample_below(&(upper.clone() - lower)) + lower + } + /// Generates random number within `(lower; upper)` range + /// + /// ## Panics + /// Panics if `upper <= lower` + fn strict_sample_range(lower: &Self, upper: &Self) -> Self { + assert!(upper > lower); + loop { + let n = Self::sample_below(&(upper.clone() - lower)) + lower; + if n > *lower && n < *upper { + return n; + } + } + } + /// Generates number within `[0; 2^bit_size)` range + fn sample(bit_size: usize) -> Self { + if bit_size == 0 { + return BigInt::zero(); + } + let mut rng = rand::thread_rng(); + let bytes = (bit_size - 1) / 8 + 1; + let mut buf: Vec = vec![0; bytes as usize]; + rng.fill_bytes(&mut buf); + Self::from_bytes(&*buf) >> u32::try_from(bytes * 8 - bit_size).unwrap() + } + /// Generates number within `[2^(bit_size-1); 2^bit_size)` range + fn strict_sample(bit_size: usize) -> Self { + if bit_size == 0 { + return BigInt::zero(); + } + loop { + let n = Self::sample(bit_size); + if n.bit_length() == bit_size { + return n; + } + } + } -#[deprecated( - since = "0.6.0", - note = "BigInt now implements zeroize::Zeroize trait, you should use it instead" -)] -pub trait ZeroizeBN { - fn zeroize_bn(&mut self); -} + /// Sets/unsets bit in the number + /// + /// ## Example + /// ``` + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// let mut n = Integer::from(0b100); + /// n.set_bit(3, true); + /// assert_eq!(n, Integer::from(0b1100)); + /// n.set_bit(0, true); + /// assert_eq!(n, Integer::from(0b1101)); + /// n.set_bit(2, false); + /// assert_eq!(n, Integer::from(0b1001)); + /// ``` + fn set_bit(&mut self, bit: usize, bit_val: bool) { + let mask = Self::one() << bit as u32; + if bit_val { + *self |= mask; + } else if self.test_bit(bit) { + *self ^= mask; + } + } + /// Tests if bit is set + /// + /// ``` + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// let n = Integer::from(0b101); + /// assert_eq!(n.test_bit(3), false); + /// assert_eq!(n.test_bit(2), true); + /// assert_eq!(n.test_bit(1), false); + /// assert_eq!(n.test_bit(0), true); + /// ``` + fn test_bit(&self, bit: usize) -> bool { + let mask = Self::one() << bit as u32; + !(mask & self).is_zero() + } + /// Length of the number in bits + /// + /// ``` + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from(0b1011).bit_length(), 4); + /// ``` + fn bit_length(&self) -> usize; -/// Converts BigInt to/from various forms of representation. -pub trait Converter: Sized { /// Returns bytes representation of the number. /// /// ## Examples /// ``` - /// # use curv::arithmetic::{BigInt, Converter}; - /// assert_eq!(BigInt::from(31).to_bytes(), &[31]); - /// assert_eq!(BigInt::from(1_000_000).to_bytes(), &[15, 66, 64]); + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from(31).to_bytes(), &[31]); + /// assert_eq!(Integer::from(1_000_000).to_bytes(), &[15, 66, 64]); /// ``` fn to_bytes(&self) -> Vec; /// Constructs BigInt from its byte representation /// /// ``` - /// # use curv::arithmetic::{BigInt, Converter}; - /// assert_eq!(BigInt::from_bytes(&[15, 66, 64]), BigInt::from(1_000_000)) + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from_bytes(&[15, 66, 64]), Integer::from(1_000_000)) /// ``` fn from_bytes(bytes: &[u8]) -> Self; @@ -68,11 +259,12 @@ pub trait Converter: Sized { /// /// ## Examples /// ``` - /// # use curv::arithmetic::{BigInt, Converter}; - /// assert_eq!(BigInt::from_hex("1f").unwrap(), BigInt::from(31)); - /// assert_eq!(BigInt::from_hex("-1f").unwrap(), BigInt::from(-31)); - /// assert_eq!(BigInt::from_hex("f4240").unwrap(), BigInt::from(1_000_000)); - /// assert_eq!(BigInt::from_hex("-f4240").unwrap(), BigInt::from(-1_000_000)); + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from_hex("1f").unwrap(), Integer::from(31)); + /// assert_eq!(Integer::from_hex("-1f").unwrap(), Integer::from(-31)); + /// assert_eq!(Integer::from_hex("f4240").unwrap(), Integer::from(1_000_000)); + /// assert_eq!(Integer::from_hex("-f4240").unwrap(), Integer::from(-1_000_000)); /// ``` fn from_hex(n: &str) -> Result { Self::from_str_radix(n, 16) @@ -85,9 +277,10 @@ pub trait Converter: Sized { /// /// ## Examples /// ``` - /// # use curv::arithmetic::{BigInt, Converter}; - /// assert_eq!(BigInt::from(31).to_str_radix(16), "1f"); - /// assert_eq!(BigInt::from(1_000_000).to_str_radix(16), "f4240"); + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from(31).to_str_radix(16), "1f"); + /// assert_eq!(Integer::from(1_000_000).to_str_radix(16), "f4240"); /// ``` fn to_str_radix(&self, radix: u8) -> String; /// Parses given radix string. @@ -96,142 +289,57 @@ pub trait Converter: Sized { /// /// ## Examples /// ``` - /// # use curv::arithmetic::{BigInt, Converter}; - /// assert_eq!(BigInt::from_str_radix("1f", 16).unwrap(), BigInt::from(31)); - /// assert_eq!(BigInt::from_str_radix("f4240", 16).unwrap(), BigInt::from(1_000_000)); + /// # use curv::arithmetic::*; + /// use curv::arithmetic::gmp::Integer; + /// assert_eq!(Integer::from_str_radix("1f", 16).unwrap(), Integer::from(31)); + /// assert_eq!(Integer::from_str_radix("f4240", 16).unwrap(), Integer::from(1_000_000)); /// ``` fn from_str_radix(s: &str, radix: u8) -> Result; -} -/// Provides basic arithmetic operators for BigInt -/// -/// Note that BigInt also implements std::ops::{Add, Mull, ...} traits, so you can -/// use them instead. -pub trait BasicOps { - fn pow(&self, exponent: u32) -> Self; - fn mul(&self, other: &Self) -> Self; - fn sub(&self, other: &Self) -> Self; - fn add(&self, other: &Self) -> Self; - fn abs(&self) -> Self; + /// Zero out this object from memory using Rust intrinsics which ensure the + /// zeroization operation is not "optimized away" by the compiler. + fn zeroize(&mut self); } -/// Modular arithmetic for BigInt -pub trait Modulo: Sized { +// Number Theory related functions +pub trait NumberTheoreticOps: Sized { /// Calculates base^(exponent) (mod m) /// /// Exponent must not be negative. Function will panic otherwise. - fn mod_pow(base: &Self, exponent: &Self, m: &Self) -> Self; + fn mod_pow(&self, exponent: &Self, modulo: &Self) -> Self; /// Calculates a * b (mod m) - fn mod_mul(a: &Self, b: &Self, modulus: &Self) -> Self; + fn mod_mul(&self, b: &Self, modulus: &Self) -> Self; /// Calculates a - b (mod m) - fn mod_sub(a: &Self, b: &Self, modulus: &Self) -> Self; + fn mod_sub(&self, b: &Self, modulus: &Self) -> Self; /// Calculates a + b (mod m) - fn mod_add(a: &Self, b: &Self, modulus: &Self) -> Self; + fn mod_add(&self, b: &Self, modulus: &Self) -> Self; /// Calculates a^-1 (mod m). Returns None if `a` and `m` are not coprimes. - fn mod_inv(a: &Self, m: &Self) -> Option; + fn mod_inv(&self, modulo: &Self) -> Option; /// Calculates a mod m fn modulus(&self, modulus: &Self) -> Self; -} - -/// Generating random BigInt -pub trait Samplable { - /// Generates random number within `[0; upper)` range - /// - /// ## Panics - /// Panics if `upper <= 0` - fn sample_below(upper: &Self) -> Self; - /// Generates random number within `[lower; upper)` range - /// - /// ## Panics - /// Panics if `upper <= lower` - fn sample_range(lower: &Self, upper: &Self) -> Self; - /// Generates random number within `(lower; upper)` range - /// - /// ## Panics - /// Panics if `upper <= lower` - fn strict_sample_range(lower: &Self, upper: &Self) -> Self; - /// Generates number within `[0; 2^bit_size)` range - fn sample(bit_size: usize) -> Self; - /// Generates number within `[2^(bit_size-1); 2^bit_size)` range - fn strict_sample(bit_size: usize) -> Self; -} - -/// Set of predicates allowing to examine BigInt -pub trait NumberTests { - /// Returns `true` if `n` is zero - /// - /// Alternatively, [BasicOps::sign] method can be used to check sign of the number. - fn is_zero(n: &Self) -> bool; - /// Returns `true` if `n` is negative - /// - /// Alternatively, [BasicOps::sign] method can be used to check sign of the number. - fn is_negative(n: &Self) -> bool; -} - -/// Extended GCD algorithm -pub trait EGCD -where - Self: Sized, -{ /// For given a, b calculates gcd(a,b), p, q such as `gcd(a,b) = a*p + b*q` /// /// ## Example /// ``` /// # use curv::arithmetic::*; - /// let (a, b) = (BigInt::from(10), BigInt::from(15)); - /// let (s, p, q) = BigInt::egcd(&a, &b); - /// assert_eq!(&s, &BigInt::from(5)); - /// assert_eq!(s, a*p + b*q); + /// use curv::arithmetic::gmp::Integer; + /// let (a, m) = (Integer::from(10), Integer::from(15)); + /// let (gcd, x, y) = Integer::egcd(&a, &m); + /// assert_eq!(&gcd, 5); + /// assert_eq!(gcd, a*x + m*y); /// ``` - fn egcd(a: &Self, b: &Self) -> (Self, Self, Self); -} + fn egcd(&self, m: &Self) -> (Self, Self, Self); -/// Bits manipulation in BigInt -pub trait BitManipulation { - /// Sets/unsets bit in the number - /// + /// Find the Greatest Common Divisor /// ## Example /// ``` /// # use curv::arithmetic::*; - /// let mut n = BigInt::from(0b100); - /// n.set_bit(3, true); - /// assert_eq!(n, BigInt::from(0b1100)); - /// n.set_bit(0, true); - /// assert_eq!(n, BigInt::from(0b1101)); - /// n.set_bit(2, false); - /// assert_eq!(n, BigInt::from(0b1001)); - /// ``` - fn set_bit(&mut self, bit: usize, bit_val: bool); - /// Tests if bit is set - /// - /// ``` - /// # use curv::arithmetic::*; - /// let n = BigInt::from(0b101); - /// assert_eq!(n.test_bit(3), false); - /// assert_eq!(n.test_bit(2), true); - /// assert_eq!(n.test_bit(1), false); - /// assert_eq!(n.test_bit(0), true); - /// ``` - fn test_bit(&self, bit: usize) -> bool; - /// Length of the number in bits - /// - /// ``` - /// # use curv::arithmetic::*; - /// assert_eq!(BigInt::from(0b1011).bit_length(), 4); - /// ``` - fn bit_length(&self) -> usize; -} - -#[deprecated( - since = "0.6.0", - note = "Use corresponding From and TryFrom traits implemented on BigInt" -)] -pub trait ConvertFrom { - fn _from(_: &T) -> Self; -} + /// use rug::Integer; + /// let (a, m) = (BigInt::from(10), BigInt::from(15)); + /// let gcd = a.gcd(m); + /// assert_eq!(gcd, 5); + fn gcd(&self, m: &Self) -> Self; -/// Utilities for searching / testing prime numbers -pub trait Primes { /// Finds next prime number using probabilistic algorithms fn next_prime(&self) -> Self; /// Probabilistically determine whether number is prime diff --git a/src/lib.rs b/src/lib.rs index 5356d21d..95f51eec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,12 +7,12 @@ #![allow(clippy::upper_case_acronyms)] -pub mod elliptic; +// pub mod elliptic; pub mod arithmetic; pub use crate::arithmetic::BigInt; -pub mod cryptographic_primitives; +// pub mod cryptographic_primitives; #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub enum ErrorKey {