@@ -56,7 +56,26 @@ 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
+ /// 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
+ }
60
79
}
61
80
62
81
/// Adapts the Fe32 iterator to encode the field elements into a bech32 address.
@@ -148,7 +167,8 @@ where
148
167
149
168
/// Iterator adaptor that converts GF32 elements to bytes.
150
169
///
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.
152
172
///
153
173
/// Note that if there are 5 or more trailing bits, the result will be that an entire field element
154
174
/// 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>> {
158
178
last_fe : Option < Fe32 > ,
159
179
bit_offset : usize ,
160
180
iter : I ,
181
+ output_incomplete_bits_zeropad : bool ,
161
182
}
162
183
163
184
impl < I > Iterator for FesToBytes < I >
@@ -177,10 +198,18 @@ where
177
198
let mut ret = last. 0 << ( 3 + bit_offset) ;
178
199
179
200
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
+ } ;
181
206
if bit_offset > 2 {
182
207
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
+ } ;
184
213
ret |= next1. 0 << ( bit_offset - 2 ) ;
185
214
ret |= next2. 0 >> ( 7 - bit_offset) ;
186
215
} else {
@@ -503,4 +532,32 @@ mod tests {
503
532
const FES : [ Fe32 ; 3 ] = [ Fe32 :: Q , Fe32 :: P , Fe32 :: Q ] ;
504
533
assert ! ( FES . iter( ) . copied( ) . fes_to_bytes( ) . bytes_to_fes( ) . eq( FES . iter( ) . copied( ) ) )
505
534
}
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
+ }
506
563
}
0 commit comments