@@ -56,7 +56,31 @@ pub trait Fe32IterExt: Sized + Iterator<Item = Fe32> {
56
56
/// are simply dropped.
57
57
#[ inline]
58
58
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
+ /// Similar to `fes_to_bytes`, but in this variant trailing bits are kept.
70
+ ///
71
+ /// If the last bits do not fill up the last output byte completely, they
72
+ /// are not dropped, but kept, and the last byte is padded with zero bits.
73
+ /// In effect this is the same as if the input was padded with zero values
74
+ /// (1 or 2), such that there are enough zero bits to fill the last byte.
75
+ /// The output is either the same as of `fes_to_bytes`, or has 1 extra byte.
76
+ #[ inline]
77
+ fn fes_to_bytes_zeropad ( mut self ) -> FesToBytes < Self > {
78
+ FesToBytes {
79
+ last_fe : self . next ( ) ,
80
+ bit_offset : 0 ,
81
+ iter : self ,
82
+ output_incomplete_bits_zeropad : true ,
83
+ }
60
84
}
61
85
62
86
/// Adapts the Fe32 iterator to encode the field elements into a bech32 address.
@@ -148,7 +172,8 @@ where
148
172
149
173
/// Iterator adaptor that converts GF32 elements to bytes.
150
174
///
151
- /// If the total number of bits is not a multiple of 8, any trailing bits are dropped.
175
+ /// If the total number of bits is not a multiple of 8. Any trailing bits are dropped,
176
+ /// unless `output_incomplete_bits_zeropad` is set, in which case they are padded with zeroes.
152
177
///
153
178
/// Note that if there are 5 or more trailing bits, the result will be that an entire field element
154
179
/// is dropped. If this occurs, the input was an invalid length for a bech32 string, but this
@@ -158,6 +183,7 @@ pub struct FesToBytes<I: Iterator<Item = Fe32>> {
158
183
last_fe : Option < Fe32 > ,
159
184
bit_offset : usize ,
160
185
iter : I ,
186
+ output_incomplete_bits_zeropad : bool ,
161
187
}
162
188
163
189
impl < I > Iterator for FesToBytes < I >
@@ -177,10 +203,18 @@ where
177
203
let mut ret = last. 0 << ( 3 + bit_offset) ;
178
204
179
205
self . last_fe = self . iter . next ( ) ;
180
- let next1 = self . last_fe ?;
206
+ let next1 = if !self . output_incomplete_bits_zeropad {
207
+ self . last_fe ?
208
+ } else {
209
+ self . last_fe . unwrap_or_default ( )
210
+ } ;
181
211
if bit_offset > 2 {
182
212
self . last_fe = self . iter . next ( ) ;
183
- let next2 = self . last_fe ?;
213
+ let next2 = if !self . output_incomplete_bits_zeropad {
214
+ self . last_fe ?
215
+ } else {
216
+ self . last_fe . unwrap_or_default ( )
217
+ } ;
184
218
ret |= next1. 0 << ( bit_offset - 2 ) ;
185
219
ret |= next2. 0 >> ( 7 - bit_offset) ;
186
220
} else {
@@ -503,4 +537,32 @@ mod tests {
503
537
const FES : [ Fe32 ; 3 ] = [ Fe32 :: Q , Fe32 :: P , Fe32 :: Q ] ;
504
538
assert ! ( FES . iter( ) . copied( ) . fes_to_bytes( ) . bytes_to_fes( ) . eq( FES . iter( ) . copied( ) ) )
505
539
}
540
+
541
+ #[ test]
542
+ fn fe32_iter_ext_zeropad_and_nozeropad ( ) {
543
+ use std:: convert:: TryFrom ;
544
+ {
545
+ // Difference is 1 output byte, containing 4 trailing bits
546
+ let fes_iter = [ 0 , 1 , 2 , 1 ] . iter ( ) . copied ( ) . map ( |b| Fe32 :: try_from ( b) . unwrap ( ) ) ;
547
+ assert_eq ! ( fes_iter. clone( ) . fes_to_bytes_zeropad( ) . collect:: <Vec <_>>( ) , [ 0 , 68 , 16 ] ) ;
548
+ assert_eq ! ( fes_iter. clone( ) . fes_to_bytes( ) . collect:: <Vec <_>>( ) , [ 0 , 68 ] ) ;
549
+ }
550
+ {
551
+ // Difference is 1 output byte, containing 1 trailing bit
552
+ let fes_iter = [ 0 , 1 , 2 , 3 , 31 ] . iter ( ) . copied ( ) . map ( |b| Fe32 :: try_from ( b) . unwrap ( ) ) ;
553
+ assert_eq ! (
554
+ fes_iter. clone( ) . fes_to_bytes_zeropad( ) . collect:: <Vec <_>>( ) ,
555
+ [ 0 , 68 , 63 , 128 ]
556
+ ) ;
557
+ assert_eq ! ( fes_iter. clone( ) . fes_to_bytes( ) . collect:: <Vec <_>>( ) , [ 0 , 68 , 63 ] ) ;
558
+ }
559
+ {
560
+ // No difference here, as the input (32*5=160 bits) has no trailing bits
561
+ let fes_iter = "w508d6qejxtdg4y5r3zarvary0c5xw7k"
562
+ . bytes ( )
563
+ . map ( |b| Fe32 :: from_char ( char:: from ( b) ) . unwrap ( ) ) ;
564
+ assert_eq ! ( fes_iter. clone( ) . fes_to_bytes_zeropad( ) . collect:: <Vec <_>>( ) , DATA ) ;
565
+ assert_eq ! ( fes_iter. clone( ) . fes_to_bytes( ) . collect:: <Vec <_>>( ) , DATA ) ;
566
+ }
567
+ }
506
568
}
0 commit comments