Skip to content

Commit 475d04b

Browse files
committed
Alternative fes_to_bytes_zeropad with no dropping of last bits
1 parent 8173170 commit 475d04b

File tree

1 file changed

+61
-4
lines changed

1 file changed

+61
-4
lines changed

src/primitives/iter.rs

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,26 @@ pub trait Fe32IterExt: Sized + Iterator<Item = Fe32> {
5656
/// are simply dropped.
5757
#[inline]
5858
fn fes_to_bytes(mut self) -> FesToBytes<Self> {
59-
FesToBytes { last_fe: self.next(), bit_offset: 0, iter: self }
59+
FesToBytes {
60+
last_fe: self.next(),
61+
bit_offset: 0,
62+
iter: self,
63+
output_incomplete_bits_zeropad: false,
64+
}
65+
}
66+
67+
/// Adapts the `Fe32` iterator to output bytes instead.
68+
///
69+
/// If the total number of bits is not a multiple of 8, trailing bits
70+
/// are padded with the needed amount of zeroes and converted.
71+
#[inline]
72+
fn fes_to_bytes_zeropad(mut self) -> FesToBytes<Self> {
73+
FesToBytes {
74+
last_fe: self.next(),
75+
bit_offset: 0,
76+
iter: self,
77+
output_incomplete_bits_zeropad: true,
78+
}
6079
}
6180

6281
/// Adapts the Fe32 iterator to encode the field elements into a bech32 address.
@@ -148,7 +167,8 @@ where
148167

149168
/// Iterator adaptor that converts GF32 elements to bytes.
150169
///
151-
/// If the total number of bits is not a multiple of 8, any trailing bits are dropped.
170+
/// If the total number of bits is not a multiple of 8. Any trailing bits are dropped,
171+
/// unless `output_incomplete_bits_zeropad` is set, in which case they are padded with zeroes.
152172
///
153173
/// Note that if there are 5 or more trailing bits, the result will be that an entire field element
154174
/// is dropped. If this occurs, the input was an invalid length for a bech32 string, but this
@@ -158,6 +178,7 @@ pub struct FesToBytes<I: Iterator<Item = Fe32>> {
158178
last_fe: Option<Fe32>,
159179
bit_offset: usize,
160180
iter: I,
181+
output_incomplete_bits_zeropad: bool,
161182
}
162183

163184
impl<I> Iterator for FesToBytes<I>
@@ -177,10 +198,18 @@ where
177198
let mut ret = last.0 << (3 + bit_offset);
178199

179200
self.last_fe = self.iter.next();
180-
let next1 = self.last_fe?;
201+
let next1 = if !self.output_incomplete_bits_zeropad {
202+
self.last_fe?
203+
} else {
204+
self.last_fe.unwrap_or_default()
205+
};
181206
if bit_offset > 2 {
182207
self.last_fe = self.iter.next();
183-
let next2 = self.last_fe?;
208+
let next2 = if !self.output_incomplete_bits_zeropad {
209+
self.last_fe?
210+
} else {
211+
self.last_fe.unwrap_or_default()
212+
};
184213
ret |= next1.0 << (bit_offset - 2);
185214
ret |= next2.0 >> (7 - bit_offset);
186215
} else {
@@ -503,4 +532,32 @@ mod tests {
503532
const FES: [Fe32; 3] = [Fe32::Q, Fe32::P, Fe32::Q];
504533
assert!(FES.iter().copied().fes_to_bytes().bytes_to_fes().eq(FES.iter().copied()))
505534
}
535+
536+
#[test]
537+
fn fe32_iter_ext_zeropad_and_nozeropad() {
538+
use std::convert::TryFrom;
539+
{
540+
// Difference is 1 output byte, containing 4 trailing bits
541+
let fes_iter = [0, 1, 2, 1].iter().copied().map(|b| Fe32::try_from(b).unwrap());
542+
assert_eq!(fes_iter.clone().fes_to_bytes_zeropad().collect::<Vec<_>>(), [0, 68, 16]);
543+
assert_eq!(fes_iter.clone().fes_to_bytes().collect::<Vec<_>>(), [0, 68]);
544+
}
545+
{
546+
// Difference is 1 output byte, containing 1 trailing bit
547+
let fes_iter = [0, 1, 2, 3, 31].iter().copied().map(|b| Fe32::try_from(b).unwrap());
548+
assert_eq!(
549+
fes_iter.clone().fes_to_bytes_zeropad().collect::<Vec<_>>(),
550+
[0, 68, 63, 128]
551+
);
552+
assert_eq!(fes_iter.clone().fes_to_bytes().collect::<Vec<_>>(), [0, 68, 63]);
553+
}
554+
{
555+
// No difference here, as the input (32*5=160 bits) has no trailing bits
556+
let fes_iter = "w508d6qejxtdg4y5r3zarvary0c5xw7k"
557+
.bytes()
558+
.map(|b| Fe32::from_char(char::from(b)).unwrap());
559+
assert_eq!(fes_iter.clone().fes_to_bytes_zeropad().collect::<Vec<_>>(), DATA);
560+
assert_eq!(fes_iter.clone().fes_to_bytes().collect::<Vec<_>>(), DATA);
561+
}
562+
}
506563
}

0 commit comments

Comments
 (0)