aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passwordmaker/base_conversion/division.rs32
-rw-r--r--src/passwordmaker/base_conversion/iterative_conversion.rs9
-rw-r--r--src/passwordmaker/base_conversion/iterative_conversion_impl.rs87
-rw-r--r--src/passwordmaker/base_conversion/mod.rs51
-rw-r--r--src/passwordmaker/base_conversion/remainders.rs43
-rw-r--r--src/passwordmaker/base_conversion/remainders_impl.rs76
-rw-r--r--src/passwordmaker/mod.rs56
7 files changed, 129 insertions, 225 deletions
diff --git a/src/passwordmaker/base_conversion/division.rs b/src/passwordmaker/base_conversion/division.rs
deleted file mode 100644
index c6fc911..0000000
--- a/src/passwordmaker/base_conversion/division.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-/// A trait that combines std::ops::Div and std::ops::Rem, as those can often be computed together.
-pub(super) trait Division<D> where Self:Sized {
- /// does in-place arbitrary-length division. Returns remainder.
- fn divide(self, divisor : &D) -> DivisionResult<Self, D>;
- fn is_zero(&self) -> bool;
-}
-
-/// Or mark your type as `UseGenericDivision` to just use `/` and `%` operators for types. Makes only sense for integers.
-pub(super) trait UseGenericDivision : Clone
- + for <'a> std::ops::Div<&'a Self, Output = Self>
- + for <'a> std::ops::Rem<&'a Self, Output = Self>
- + Default
- + Eq {}
-
- impl<U> Division<U> for U
- where U: UseGenericDivision
-{
- fn divide(self, divisor : &Self) -> DivisionResult<Self, Self> {
- DivisionResult {
- result: self.clone().div(divisor),
- remainder: self.rem(divisor)
- }
- }
- fn is_zero(&self) -> bool {
- *self == Self::default()
- }
-}
-
-pub(super) struct DivisionResult<T, U> {
- pub result : T,
- pub remainder : U,
-} \ No newline at end of file
diff --git a/src/passwordmaker/base_conversion/iterative_conversion.rs b/src/passwordmaker/base_conversion/iterative_conversion.rs
index 94d28c0..9b55141 100644
--- a/src/passwordmaker/base_conversion/iterative_conversion.rs
+++ b/src/passwordmaker/base_conversion/iterative_conversion.rs
@@ -12,7 +12,7 @@ use std::convert::TryInto;
use std::ops::{Mul, DivAssign};
use std::iter::successors;
-pub(super) struct IterativeBaseConversion<V,B>{
+pub(crate) struct IterativeBaseConversion<V,B>{
current_value : V,
current_base_potency : V,
remaining_digits : usize,
@@ -141,4 +141,11 @@ mod iterative_conversion_tests{
assert_eq!(i.len(), 32);
assert_eq!(i.skip_while(|x| *x == 0_u64).collect::<Vec<_>>(), vec![7, 5, 0xA, 0x10, 0xC, 0xC, 3, 0xD, 3, 0xA, 3,8,4,8,3]);
}
+ #[test]
+ fn test_simple_u128_to_base_39_conversion(){
+ let i = IterativeBaseConversion::new(MyU128(1234567890123456789u128), 39u64);
+ assert_eq!(i.len(), 25);
+ // 3YPRS4FaC1KU
+ assert_eq!(i.skip_while(|x| *x == 0_u64).collect::<Vec<_>>(), vec![3, 34, 25, 27, 28, 4, 15, 36, 12, 1, 20, 30]);
+ }
} \ No newline at end of file
diff --git a/src/passwordmaker/base_conversion/iterative_conversion_impl.rs b/src/passwordmaker/base_conversion/iterative_conversion_impl.rs
index be1d851..3dceb9b 100644
--- a/src/passwordmaker/base_conversion/iterative_conversion_impl.rs
+++ b/src/passwordmaker/base_conversion/iterative_conversion_impl.rs
@@ -15,7 +15,13 @@ use std::{ops::{DivAssign, Mul, SubAssign}, convert::{TryFrom, TryInto}, fmt::Di
use super::iterative_conversion::RemAssignWithQuotient;
//Type to be used as V, with usize as B.
-struct SixteenBytes(u128);
+pub(crate) struct SixteenBytes(u128);
+
+impl SixteenBytes{
+ pub(super) fn new(value : u128) -> Self {
+ SixteenBytes(value)
+ }
+}
//just for convenience
impl From<u128> for SixteenBytes{
@@ -58,7 +64,7 @@ impl Mul<&usize> for &SixteenBytes{
//We cannot directly implement all the Foreign traits on arrays directly. So, newtypes again.
#[derive(PartialEq, PartialOrd, Ord, Eq, Clone)]
-struct ArbitraryBytes<const N : usize>([u32;N]);
+pub(crate) struct ArbitraryBytes<const N : usize>([u32;N]);
//Const generics are still a bit limited -> let's just implement From for the exact types we need.
impl From<&usize> for ArbitraryBytes<5>{
@@ -116,7 +122,7 @@ impl From<&u32> for ArbitraryBytes<8>{
}
//workaround for lack of proper const-generic support.
-trait PadWithAZero{
+pub(super) trait PadWithAZero{
type Output;
fn pad_with_a_zero(&self) -> Self::Output;
}
@@ -160,7 +166,7 @@ impl<const N : usize> DivAssign<&usize> for ArbitraryBytes<N>{
}
#[derive(Debug, Clone, Copy)]
-struct ArbitraryBytesToUsizeError;
+pub(crate) struct ArbitraryBytesToUsizeError;
impl Display for ArbitraryBytesToUsizeError{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "conversion from arbitrary sized int-array to usize failed")
@@ -203,7 +209,7 @@ impl<const N : usize> TryFrom<&ArbitraryBytes<N>> for usize{
}
#[derive(Debug, Clone, Copy)]
-struct ArbitraryBytesToU32Error;
+pub(crate) struct ArbitraryBytesToU32Error;
impl Display for ArbitraryBytesToU32Error{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "conversion from arbitrary sized int-array to u32 failed")
@@ -233,7 +239,7 @@ impl<const N : usize> Mul<&usize> for &ArbitraryBytes<N>{
//somewhere we need this clone, can just as well be in here...
let mut result = self.0.clone();
let carry = result.iter_mut().rev().fold(UsizeAndFour::default(), |carry, digit|{
- assert_eq!(carry, carry & (usize::MAX as UsizeAndFour)); //carry always has to fit in usize, otherwise something is terribly wrong.
+ debug_assert_eq!(carry, carry & (usize::MAX as UsizeAndFour)); //carry always has to fit in usize, otherwise something is terribly wrong.
let res = (*digit as UsizeAndFour) * (*rhs as UsizeAndFour) + carry;
*digit = res as u32;
res >> 32
@@ -276,7 +282,7 @@ impl<const N : usize> Mul<u32> for ArbitraryBytes<N>{
fn mul(mut self, rhs: u32) -> Self::Output {
//somewhere we need this clone, can just as well be in here...
let carry = self.0.iter_mut().rev().fold(u64::default(), |carry, digit|{
- assert_eq!(carry, carry & (u32::MAX as u64)); //carry always has to fit in usize, otherwise something is terribly wrong.
+ debug_assert_eq!(carry, carry & (u32::MAX as u64)); //carry always has to fit in usize, otherwise something is terribly wrong.
let res = (*digit as u64) * (rhs as u64) + carry;
*digit = res as u32;
res >> 32
@@ -301,31 +307,35 @@ impl<const N : usize> SubAssign<&ArbitraryBytes<N>> for ArbitraryBytes<N>{
1
}
});
- assert_eq!(carry,0);
+ debug_assert_eq!(carry,0);
}
}
impl<const N : usize> ArbitraryBytes<N>{
+ pub(super) fn new(data : [u32;N]) -> Self {
+ ArbitraryBytes(data)
+ }
+
/// Replaces self with Quotient and returns Remainder
fn div_assign_with_remainder_usize(&mut self, rhs: &usize) -> usize {
#[cfg(target_pointer_width = "64")]
type UsizeAndFour = u128;
#[cfg(not(target_pointer_width = "64"))]
type UsizeAndFour = u64;
- assert!((UsizeAndFour::MAX >> 32) as u128 >= usize::MAX as u128);
+ debug_assert!((UsizeAndFour::MAX >> 32) as u128 >= usize::MAX as u128);
let divisor : UsizeAndFour = *rhs as UsizeAndFour;
let remainder = self.0.iter_mut().fold(0 as UsizeAndFour,|carry, current| {
- assert_eq!(carry, carry & (usize::MAX as UsizeAndFour)); //carry has to be lower than divisor, and divisor is usize.
+ debug_assert_eq!(carry, carry & (usize::MAX as UsizeAndFour)); //carry has to be lower than divisor, and divisor is usize.
let carry_shifted = carry << 32;
let dividend = (carry_shifted) + (*current as UsizeAndFour);
let ratio = dividend / divisor;
- assert_eq!(ratio, ratio & 0xffff_ffff); //this is fine. The first digit after re-adding the carry is alwys zero.
+ debug_assert_eq!(ratio, ratio & 0xffff_ffff); //this is fine. The first digit after re-adding the carry is alwys zero.
*current = (ratio) as u32;
dividend - (*current as UsizeAndFour) * divisor
});
- assert_eq!(remainder, remainder & (usize::MAX as UsizeAndFour));
+ debug_assert_eq!(remainder, remainder & (usize::MAX as UsizeAndFour));
remainder as usize
}
@@ -333,15 +343,15 @@ impl<const N : usize> ArbitraryBytes<N>{
fn div_assign_with_remainder_u32(&mut self, rhs: &u32) -> u32 {
let divisor : u64 = *rhs as u64;
let remainder = self.0.iter_mut().fold(0 as u64,|carry, current| {
- assert_eq!(carry, carry & (u32::MAX as u64)); //carry has to be lower than divisor, and divisor is usize.
+ debug_assert_eq!(carry, carry & (u32::MAX as u64)); //carry has to be lower than divisor, and divisor is usize.
let carry_shifted = carry << 32;
let dividend = (carry_shifted) + (*current as u64);
let ratio = dividend / divisor;
- assert_eq!(ratio, ratio & 0xffff_ffff); //this is fine. The first digit after re-adding the carry is alwys zero.
+ debug_assert_eq!(ratio, ratio & 0xffff_ffff); //this is fine. The first digit after re-adding the carry is alwys zero.
*current = (ratio) as u32;
dividend - (*current as u64) * divisor
});
- assert_eq!(remainder, remainder & (u32::MAX as u64));
+ debug_assert_eq!(remainder, remainder & (u32::MAX as u64));
remainder as u32
}
@@ -355,10 +365,10 @@ impl<const N : usize> ArbitraryBytes<N>{
where Self : PadWithAZero<Output = ArbitraryBytes<M>> +
for<'a> From<&'a usize>
{
- assert!(M == N+1);
+ debug_assert!(M == N+1);
//first we need to find n (number of digits in divisor)
let n_digits_divisor= N - divisor.find_first_nonzero_digit();
- assert!(n_digits_divisor > 1);
+ debug_assert!(n_digits_divisor > 1);
//and same in the non-normalized dividend
let m_plus_n_digits_dividend = N - self.find_first_nonzero_digit();
let m_extra_digits_dividend = m_plus_n_digits_dividend - n_digits_divisor;
@@ -376,7 +386,7 @@ impl<const N : usize> ArbitraryBytes<N>{
let divisor_second_significant_digit = divisor.get_digit_from_right(n_digits_divisor-2) as u64;
//step D2, D7: the loop.
- for j in m_extra_digits_dividend..=0 {
+ for j in (0..=m_extra_digits_dividend).rev() {
//Step D3: Guess a digit
let guess_dividend = ((dividend.get_digit_from_right(j+n_digits_divisor) as u64)<<32) + (dividend.get_digit_from_right(j + n_digits_divisor - 1) as u64);
let mut guesstimate = guess_dividend/guess_divisor;
@@ -393,7 +403,7 @@ impl<const N : usize> ArbitraryBytes<N>{
//I'm too tired to do this by the book. If this thing is gonna blow, we can just as well increase our guesstimate by one and call it a day.
//In any case, this does only happen in _very_ rare cases. Soo:
//Steps D4-D6.
- assert!(guesstimate & (u32::MAX as u64) == guesstimate); //Knuth says this is a one-place number, and I trust him.
+ debug_assert!(guesstimate & (u32::MAX as u64) == guesstimate); //Knuth says this is a one-place number, and I trust him.
let mut guesstimate = guesstimate as u32;
let mut s = (divisor.clone() * guesstimate).expect("Multipliation by a digit cannot overflow for a padded type.");
let will_overflow =
@@ -402,7 +412,7 @@ impl<const N : usize> ArbitraryBytes<N>{
if will_overflow {
guesstimate -= 1;
s -= &divisor;
- assert!(std::cmp::Ord::cmp(&dividend.0[(M - 1 - (j+n_digits_divisor))..=(M - 1 - j)], &s.0[(M - 1 - n_digits_divisor)..=(M - 1)]) != Ordering::Less)
+ debug_assert!(std::cmp::Ord::cmp(&dividend.0[(M - 1 - (j+n_digits_divisor))..=(M - 1 - j)], &s.0[(M - 1 - n_digits_divisor)..=(M - 1)]) != Ordering::Less)
}
slice_sub_assign(&mut dividend.0[(M - 1 - (j+n_digits_divisor))..=(M - 1 - j)], &s.0[(M - 1 - n_digits_divisor)..=(M - 1)]);
quotient.set_digit_from_right(guesstimate, j);
@@ -428,7 +438,7 @@ impl<const N : usize> ArbitraryBytes<N>{
}
fn slice_sub_assign(lhs : &mut [u32], rhs: &[u32]){
- assert_eq!(lhs.len(), rhs.len());
+ debug_assert_eq!(lhs.len(), rhs.len());
let carry = lhs.iter_mut().zip(rhs.iter()).rev().fold(0_u64,|carry,(i,s)| {
let s = (*s as u64) + carry;
if *i as u64 >= s {
@@ -439,5 +449,38 @@ fn slice_sub_assign(lhs : &mut [u32], rhs: &[u32]){
1
}
});
- assert_eq!(carry,0);
+ debug_assert_eq!(carry,0);
+}
+
+#[cfg(test)]
+mod iterative_conversion_impl_tests{
+ use super::*;
+
+ #[test]
+ fn knuth_add_back_test(){
+ let mut dividend = ArbitraryBytes::new([
+ //m = 3, n=5
+ u32::MAX,
+ u32::MAX,
+ u32::MAX-1,
+ u32::MAX,
+ u32::MAX,
+ 0,
+ 0,
+ 3
+ ]);
+ let divisor = ArbitraryBytes::new([
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ u32::MAX,
+ u32::MAX,
+ u32::MAX,
+ ]);
+ let result = dividend.rem_assign_with_quotient(&divisor);
+ assert_eq!(dividend.0, [0,0,0,0,0,0,0,2]);
+ assert_eq!(result.0, [0,0,0,u32::MAX,u32::MAX, u32::MAX, u32::MAX, u32::MAX]);
+ }
} \ No newline at end of file
diff --git a/src/passwordmaker/base_conversion/mod.rs b/src/passwordmaker/base_conversion/mod.rs
index 4ae7653..b1ffedf 100644
--- a/src/passwordmaker/base_conversion/mod.rs
+++ b/src/passwordmaker/base_conversion/mod.rs
@@ -1,60 +1,63 @@
use std::convert::TryInto;
+use iterative_conversion_impl::PadWithAZero;
+pub(super) use iterative_conversion::IterativeBaseConversion;
+pub(super) use iterative_conversion_impl::{SixteenBytes, ArbitraryBytes};
-use remainders::CalcRemainders;
-
-mod division;
mod iterative_conversion;
mod iterative_conversion_impl;
-mod remainders;
-mod remainders_impl;
-
/// Converts an input to a different base (which fits in usize). Returns the digits starting at the most significant one.
pub(super) trait BaseConversion {
+ type Output : ExactSizeIterator<Item=usize>;
// return type is subject to change. Hopefully soon the math will be rewritten, so we can skip the Vec and IntoIter.
// will have to remain an ExactSizeIterator though.
- fn convert_to_base(self, base : usize) -> std::iter::Rev<std::vec::IntoIter<usize>>;
+ fn convert_to_base(self, base : usize) -> Self::Output;
}
-impl<T, const N : usize> BaseConversion for T where T : ToI32Array<Output = [u32;N]>{
- fn convert_to_base(self, base : usize) -> std::iter::Rev<std::vec::IntoIter<usize>> {
- self.to_int_array().calc_remainders(base).collect::<Vec<_>>().into_iter().rev()
+impl<T, const N : usize, const M : usize> BaseConversion for T
+ where T : ToArbitraryBytes<Output = ArbitraryBytes<N>>,
+ for<'a> T::Output: From<&'a usize> + From<&'a u32> + PadWithAZero<Output = ArbitraryBytes<M>>,
+{
+ type Output = IterativeBaseConversion<ArbitraryBytes<N>, usize>;
+ fn convert_to_base(self, base : usize) -> Self::Output {
+ IterativeBaseConversion::new(self.to_arbitrary_bytes(), base)
}
}
impl BaseConversion for [u8;16]{
- fn convert_to_base(self, base : usize) -> std::iter::Rev<std::vec::IntoIter<usize>> {
- u128::from_be_bytes(self).calc_remainders(base as u128).map(|ll| ll as usize).collect::<Vec<_>>().into_iter().rev()
+ type Output = IterativeBaseConversion<SixteenBytes,usize>;
+ fn convert_to_base(self, base : usize) -> IterativeBaseConversion<SixteenBytes,usize> {
+ IterativeBaseConversion::new(SixteenBytes::new(u128::from_be_bytes(self)), base)
}
}
// Rust 1.52 only has a very limited support for const generics. This means, we'll have to live with this not-too-constrained solution...
-pub(super) trait ToI32Array {
+pub(super) trait ToArbitraryBytes {
type Output;
- fn to_int_array(self) -> Self::Output;
+ fn to_arbitrary_bytes(self) -> Self::Output;
}
//this could of course be done in a generic manner, but it's ugly without array_mut, which we don't have in Rust 1.52.
//Soo, pedestrian's approach :D
-impl ToI32Array for [u8;20] {
- type Output = [u32; 5];
- fn to_int_array(self) -> [u32; 5] {
- [
+impl ToArbitraryBytes for [u8;20] {
+ type Output = ArbitraryBytes<5>;
+ fn to_arbitrary_bytes(self) -> ArbitraryBytes<5> {
+ ArbitraryBytes::new([
u32::from_be_bytes(self[0..4].try_into().unwrap()),
u32::from_be_bytes(self[4..8].try_into().unwrap()),
u32::from_be_bytes(self[8..12].try_into().unwrap()),
u32::from_be_bytes(self[12..16].try_into().unwrap()),
u32::from_be_bytes(self[16..20].try_into().unwrap()),
- ]
+ ])
}
}
-impl ToI32Array for [u8;32] {
- type Output = [u32; 8];
- fn to_int_array(self) -> [u32; 8] {
- [
+impl ToArbitraryBytes for [u8;32] {
+ type Output = ArbitraryBytes<8>;
+ fn to_arbitrary_bytes(self) -> ArbitraryBytes<8> {
+ ArbitraryBytes::new([
u32::from_be_bytes(self[0..4].try_into().unwrap()),
u32::from_be_bytes(self[4..8].try_into().unwrap()),
u32::from_be_bytes(self[8..12].try_into().unwrap()),
@@ -63,6 +66,6 @@ impl ToI32Array for [u8;32] {
u32::from_be_bytes(self[20..24].try_into().unwrap()),
u32::from_be_bytes(self[24..28].try_into().unwrap()),
u32::from_be_bytes(self[28..32].try_into().unwrap()),
- ]
+ ])
}
} \ No newline at end of file
diff --git a/src/passwordmaker/base_conversion/remainders.rs b/src/passwordmaker/base_conversion/remainders.rs
deleted file mode 100644
index 344fab2..0000000
--- a/src/passwordmaker/base_conversion/remainders.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use super::division::{Division, DivisionResult};
-
-/// Trait used for the old base conversion.
-pub(super) trait CalcRemainders<T, D>{
- fn calc_remainders(self, divisor : D) -> Remainders<T,D>;
-}
-
-impl<T, D> CalcRemainders<T, D> for T
- where T:Division<D>
-{
- fn calc_remainders(self, divisor : D) -> Remainders<T, D> {
- Remainders::new(self,divisor)
- }
-}
-
-pub(super) struct Remainders<T, U>{
- value : Option<T>,
- divisor : U,
-}
-
-impl<U, T:Division<U>> Remainders<T, U> {
- fn new(value : T, divisor : U) -> Self {
- let value = if value.is_zero() { None } else { Some(value) };
- Remainders {
- value,
- divisor,
- }
- }
-}
-
-impl<U, T:Division<U>> Iterator for Remainders<T,U>{
- type Item=U;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(v) = self.value.take() {
- let DivisionResult{result, remainder} = v.divide(&self.divisor);
- self.value = if result.is_zero() { None } else { Some(result) };
- Some(remainder)
- } else {
- None
- }
- }
-} \ No newline at end of file
diff --git a/src/passwordmaker/base_conversion/remainders_impl.rs b/src/passwordmaker/base_conversion/remainders_impl.rs
deleted file mode 100644
index c2431bb..0000000
--- a/src/passwordmaker/base_conversion/remainders_impl.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use super::division::{Division, UseGenericDivision, DivisionResult};
-
-impl UseGenericDivision for u128{} //for Md4, Md5
-
-impl<const N : usize> Division<usize> for [u32;N] {
- #[allow(clippy::cast_possible_truncation)]
- fn divide(mut self, divisor : &usize) -> DivisionResult<Self, usize> {
- #[cfg(target_pointer_width = "64")]
- type UsizeAndFour = u128;
- #[cfg(not(target_pointer_width = "64"))]
- type UsizeAndFour = u64;
- assert!((UsizeAndFour::MAX >> 32) as u128 >= usize::MAX as u128);
-
- //uses mutation, because why not? self is owned after all :D
- let divisor : UsizeAndFour = *divisor as UsizeAndFour;
- let remainder = self.iter_mut().fold(0 as UsizeAndFour,|carry, current| {
- assert_eq!(carry, carry & (usize::MAX as UsizeAndFour)); //carry has to be lower than divisor, and divisor is usize.
- let carry_shifted = carry << 32;
- let dividend = (carry_shifted) + (*current as UsizeAndFour);
- let ratio = dividend / divisor;
- assert_eq!(ratio, ratio & 0xffff_ffff); //this is fine. The first digit after re-adding the carry is alwys zero.
- *current = (ratio) as u32;
- dividend - (*current as UsizeAndFour) * divisor
- });
- assert_eq!(remainder, remainder & (usize::MAX as UsizeAndFour));
- let remainder = remainder as usize;
- DivisionResult{
- result: self,
- remainder,
- }
- }
-
- fn is_zero(&self) -> bool {
- self.iter().all(|x| *x == 0)
- }
-}
-
-#[cfg(test)]
-mod remainders_tests{
- use super::super::remainders::CalcRemainders;
-
- use super::*;
- #[test]
- fn test_generic_division(){
- let v = 50u128;
- let d = 7u128;
- let DivisionResult{result, remainder}=v.divide(&d);
- assert_eq!(7, result);
- assert_eq!(1, remainder);
- }
-
- #[test]
- fn test_remainders() {
- //relies on generic division.
- let v = 141u128;
- let d = 3u128;
- let results : Vec<u128> = v.calc_remainders(d).collect();
- assert_eq!(results, vec![0u128,2u128,0u128,2u128,1u128])
- }
-
- #[test]
- fn test_array_divide() {
- let dividend_int = 0xe7f1ec3a5f35af805407a8a531eefb79u128;
- let dividend = [(dividend_int >> 96) as u32, ((dividend_int >> 64) & 0xffffffff) as u32, ((dividend_int >> 32) & 0xffffffff) as u32, (dividend_int & 0xffffffff) as u32];
- #[cfg(target_pointer_width = "64")]
- let divisor = 1531534813576487;
- #[cfg(not(target_pointer_width = "64"))]
- let divisor = 1531534813;
- let result_int = dividend_int / (divisor as u128);
- let remainder_int = dividend_int % (divisor as u128);
- let result = dividend.divide(&divisor);
- assert_eq!(result.result, [(result_int >> 96) as u32, ((result_int >> 64) & 0xffffffff) as u32, ((result_int >> 32) & 0xffffffff) as u32, (result_int & 0xffffffff) as u32]);
- assert_eq!(remainder_int, result.remainder as u128);
- }
-
-} \ No newline at end of file
diff --git a/src/passwordmaker/mod.rs b/src/passwordmaker/mod.rs
index a96698d..5e51ee9 100644
--- a/src/passwordmaker/mod.rs
+++ b/src/passwordmaker/mod.rs
@@ -1,10 +1,13 @@
-use std::iter::repeat;
+use std::iter::SkipWhile;
+
use unicode_segmentation::UnicodeSegmentation;
use leet::LeetReplacementTable;
use grapheme::Grapheme;
use base_conversion::BaseConversion;
+use self::base_conversion::{IterativeBaseConversion, SixteenBytes, ArbitraryBytes};
+
use super::Hasher;
mod base_conversion;
@@ -94,7 +97,6 @@ impl<'y, H : super::HasherList> super::PasswordMaker<'y, H>{
let message = yeet_upper_bytes(&message).collect::<Vec<u8>>();
let hash = H::MD5::hash(&message);
let grapheme_indices = hash.convert_to_base(characters.len());
- let grapheme_indices = yoink_additional_graphemes_for_06_if_needed(grapheme_indices);
GetGraphemesIterator { graphemes : characters, inner: GetGraphemesIteratorInner::V06(grapheme_indices)}
}
@@ -112,7 +114,6 @@ impl<'y, H : super::HasherList> super::PasswordMaker<'y, H>{
let data = yeet_upper_bytes(data);
let hash = hmac::hmac::<H::MD5,_,_>(key, data);
let grapheme_indices = hash.convert_to_base(characters.len());
- let grapheme_indices = yoink_additional_graphemes_for_06_if_needed(grapheme_indices);
GetGraphemesIterator { graphemes : characters, inner: GetGraphemesIteratorInner::V06(grapheme_indices)}
}
@@ -128,17 +129,17 @@ impl<'y, H : super::HasherList> super::PasswordMaker<'y, H>{
let data = leetified_data.as_deref().unwrap_or(data);
let grapheme_indices = match algo {
Algorithm::Md4 =>
- modern_hmac_to_grapheme_indices::<H::MD4>(&key, data, characters.len()),
+ GetGraphemesIteratorInner::Modern16(modern_hmac_to_grapheme_indices::<H::MD4>(&key, data, characters.len()).skip_while(is_zero)),
Algorithm::Md5 =>
- modern_hmac_to_grapheme_indices::<H::MD5>(&key, data, characters.len()),
+ GetGraphemesIteratorInner::Modern16(modern_hmac_to_grapheme_indices::<H::MD5>(&key, data, characters.len()).skip_while(is_zero)),
Algorithm::Sha1 =>
- modern_hmac_to_grapheme_indices::<H::SHA1>(&key, data, characters.len()),
+ GetGraphemesIteratorInner::Modern20(modern_hmac_to_grapheme_indices::<H::SHA1>(&key, data, characters.len()).skip_while(is_zero)),
Algorithm::Sha256 =>
- modern_hmac_to_grapheme_indices::<H::SHA256>(&key, data, characters.len()),
+ GetGraphemesIteratorInner::Modern32(modern_hmac_to_grapheme_indices::<H::SHA256>(&key, data, characters.len()).skip_while(is_zero)),
Algorithm::Ripemd160 =>
- modern_hmac_to_grapheme_indices::<H::RIPEMD160>(&key, data, characters.len()),
+ GetGraphemesIteratorInner::Modern20(modern_hmac_to_grapheme_indices::<H::RIPEMD160>(&key, data, characters.len()).skip_while(is_zero)),
};
- GetGraphemesIterator { graphemes : characters, inner: GetGraphemesIteratorInner::Modern(grapheme_indices)}
+ GetGraphemesIterator { graphemes : characters, inner: grapheme_indices}
}
fn generate_password_part_modern<'a>(
@@ -152,17 +153,17 @@ impl<'y, H : super::HasherList> super::PasswordMaker<'y, H>{
let message = pre_leet_level.as_ref().map(|l| l.leetify(&message)).unwrap_or(message);
let grapheme_indices = match algo {
Algorithm::Md4 =>
- modern_message_to_grapheme_indices::<H::MD4>(&message, characters.len()),
+ GetGraphemesIteratorInner::Modern16(modern_message_to_grapheme_indices::<H::MD4>(&message, characters.len()).skip_while(is_zero)),
Algorithm::Md5 =>
- modern_message_to_grapheme_indices::<H::MD5>(&message,characters.len()),
+ GetGraphemesIteratorInner::Modern16(modern_message_to_grapheme_indices::<H::MD5>(&message,characters.len()).skip_while(is_zero)),
Algorithm::Sha1 =>
- modern_message_to_grapheme_indices::<H::SHA1>(&message,characters.len()),
+ GetGraphemesIteratorInner::Modern20(modern_message_to_grapheme_indices::<H::SHA1>(&message,characters.len()).skip_while(is_zero)),
Algorithm::Sha256 =>
- modern_message_to_grapheme_indices::<H::SHA256>(&message,characters.len()),
+ GetGraphemesIteratorInner::Modern32(modern_message_to_grapheme_indices::<H::SHA256>(&message,characters.len()).skip_while(is_zero)),
Algorithm::Ripemd160 =>
- modern_message_to_grapheme_indices::<H::RIPEMD160>(&message,characters.len()),
+ GetGraphemesIteratorInner::Modern20(modern_message_to_grapheme_indices::<H::RIPEMD160>(&message,characters.len()).skip_while(is_zero)),
};
- GetGraphemesIterator { graphemes : characters, inner: GetGraphemesIteratorInner::Modern(grapheme_indices)}
+ GetGraphemesIterator { graphemes : characters, inner: grapheme_indices}
}
}
@@ -195,9 +196,15 @@ fn combine_prefix_password_suffix<'a, T : Iterator<Item=Grapheme<'a>>>(password:
.collect()
}
+fn is_zero(i : &usize) -> bool {
+ *i == 0
+}
+
enum GetGraphemesIteratorInner {
- Modern(std::iter::Rev<std::vec::IntoIter<usize>>),
- V06(std::iter::Chain<std::iter::Take<std::iter::Repeat<usize>>, std::iter::Rev<std::vec::IntoIter<usize>>>)
+ Modern16(SkipWhile<IterativeBaseConversion<SixteenBytes,usize>,fn(&usize)->bool>),
+ Modern20(SkipWhile<IterativeBaseConversion<ArbitraryBytes<5>,usize>,fn(&usize)->bool>),
+ Modern32(SkipWhile<IterativeBaseConversion<ArbitraryBytes<8>,usize>,fn(&usize)->bool>),
+ V06(IterativeBaseConversion<SixteenBytes,usize>)
}
struct GetGraphemesIterator<'a> {
graphemes : &'a Vec<Grapheme<'a>>,
@@ -212,21 +219,23 @@ impl<'a> Iterator for GetGraphemesIterator<'a> {
fn next(&mut self) -> Option<Self::Item> {
let idx = match &mut self.inner {
- GetGraphemesIteratorInner::Modern(i) => i.next(),
+ GetGraphemesIteratorInner::Modern16(i) => i.next(),
+ GetGraphemesIteratorInner::Modern20(i) => i.next(),
+ GetGraphemesIteratorInner::Modern32(i) => i.next(),
GetGraphemesIteratorInner::V06(i) => i.next(),
};
idx.and_then(|idx| self.graphemes.get(idx).cloned())
}
}
-fn modern_hmac_to_grapheme_indices<T>(key : &str, data: &str, divisor : usize) -> std::iter::Rev<std::vec::IntoIter<usize>>
+fn modern_hmac_to_grapheme_indices<T>(key : &str, data: &str, divisor : usize) -> <<T as Hasher>::Output as BaseConversion>::Output
where T:Hasher,
<T as Hasher>::Output: BaseConversion + AsRef<[u8]>
{
hmac::hmac::<T,_,_>(key.bytes(), data.bytes()).convert_to_base(divisor)
}
-fn modern_message_to_grapheme_indices<T>(data: &str, divisor : usize) -> std::iter::Rev<std::vec::IntoIter<usize>>
+fn modern_message_to_grapheme_indices<T>(data: &str, divisor : usize) -> <<T as Hasher>::Output as BaseConversion>::Output
where T:Hasher,
<T as Hasher>::Output: BaseConversion
{
@@ -307,11 +316,4 @@ impl AlgoSelection {
#[allow(clippy::cast_possible_truncation)] //clippy, stop complaining. Truncating is the very purpose of this function...
fn yeet_upper_bytes(input : &str) -> impl Iterator<Item=u8> + Clone + '_ {
input.encode_utf16().map(|wide_char| wide_char as u8)
-}
-
-//signature subject to change, but need named types...
-fn yoink_additional_graphemes_for_06_if_needed(input : std::iter::Rev<std::vec::IntoIter<usize>>)
- -> std::iter::Chain<std::iter::Take<std::iter::Repeat<usize>>, std::iter::Rev<std::vec::IntoIter<usize>>>
-{
- repeat(0_usize).take(32-input.len()).chain(input)
} \ No newline at end of file