@@ -51,8 +51,11 @@ use alloc::{string::String, vec::Vec};
5151use core:: convert:: { Infallible , TryFrom } ;
5252use core:: { fmt, mem} ;
5353
54+ pub use crate :: primitives:: checksum:: Checksum ;
55+ use crate :: primitives:: checksum:: { self , PackedFe32 } ;
5456use crate :: primitives:: hrp;
5557pub use crate :: primitives:: hrp:: Hrp ;
58+ pub use crate :: primitives:: { Bech32 , Bech32m } ;
5659
5760mod error;
5861pub mod primitives;
@@ -101,50 +104,26 @@ const CHECKSUM_LENGTH: usize = 6;
101104
102105/// Allocationless Bech32 writer that accumulates the checksum data internally and writes them out
103106/// in the end.
104- pub struct Bech32Writer < ' a > {
107+ pub struct Bech32Writer < ' a , Ck : Checksum > {
105108 formatter : & ' a mut dyn fmt:: Write ,
106- chk : u32 ,
107- variant : Variant ,
109+ engine : checksum:: Engine < Ck > ,
108110}
109111
110- impl < ' a > Bech32Writer < ' a > {
112+ impl < ' a , Ck : Checksum > Bech32Writer < ' a , Ck > {
111113 /// Creates a new writer that can write a bech32 string without allocating itself.
112114 ///
113115 /// This is a rather low-level API and doesn't check the HRP or data length for standard
114116 /// compliance.
115- pub fn new (
116- hrp : Hrp ,
117- variant : Variant ,
118- fmt : & ' a mut dyn fmt:: Write ,
119- ) -> Result < Bech32Writer < ' a > , fmt:: Error > {
120- let mut writer = Bech32Writer { formatter : fmt, chk : 1 , variant } ;
117+ fn new ( hrp : Hrp , fmt : & ' a mut dyn fmt:: Write ) -> Result < Bech32Writer < ' a , Ck > , fmt:: Error > {
118+ let mut engine = checksum:: Engine :: new ( ) ;
119+ engine. input_hrp ( & hrp) ;
121120
122121 for c in hrp. lowercase_char_iter ( ) {
123- writer. formatter . write_char ( c) ?;
124- }
125- writer. formatter . write_char ( SEP ) ?;
126-
127- // expand HRP
128- for b in hrp. lowercase_byte_iter ( ) {
129- writer. polymod_step ( u5 ( b >> 5 ) ) ;
122+ fmt. write_char ( c) ?;
130123 }
131- writer. polymod_step ( u5 ( 0 ) ) ;
132- for b in hrp. lowercase_byte_iter ( ) {
133- writer. polymod_step ( u5 ( b & 0x1f ) ) ;
134- }
135-
136- Ok ( writer)
137- }
138-
139- fn polymod_step ( & mut self , v : u5 ) {
140- let b = ( self . chk >> 25 ) as u8 ;
141- self . chk = ( self . chk & 0x01ff_ffff ) << 5 ^ ( u32:: from ( * v. as_ref ( ) ) ) ;
124+ fmt. write_char ( SEP ) ?;
142125
143- for ( i, item) in GEN . iter ( ) . enumerate ( ) {
144- if ( b >> i) & 1 == 1 {
145- self . chk ^= item;
146- }
147- }
126+ Ok ( Bech32Writer { formatter : fmt, engine } )
148127 }
149128
150129 /// Writes out the checksum at the end.
@@ -158,31 +137,31 @@ impl<'a> Bech32Writer<'a> {
158137
159138 /// Calculates and writes a checksum to `self`.
160139 fn write_checksum ( & mut self ) -> fmt:: Result {
161- // Pad with 6 zeros
162- for _ in 0 ..CHECKSUM_LENGTH {
163- self . polymod_step ( u5 ( 0 ) )
164- }
140+ self . engine . input_target_residue ( ) ;
165141
166- let plm: u32 = self . chk ^ self . variant . constant ( ) ;
142+ let mut checksum_remaining = self :: CHECKSUM_LENGTH ;
143+ while checksum_remaining > 0 {
144+ checksum_remaining -= 1 ;
167145
168- for p in 0 ..CHECKSUM_LENGTH {
169- self . formatter . write_char ( u5 ( ( ( plm >> ( 5 * ( 5 - p) ) ) & 0x1f ) as u8 ) . to_char ( ) ) ?;
146+ let fe = u5:: try_from ( self . engine . residue ( ) . unpack ( checksum_remaining) )
147+ . expect ( "unpack returns valid field element" ) ;
148+ self . formatter . write_char ( fe. to_char ( ) ) ?;
170149 }
171150
172151 Ok ( ( ) )
173152 }
174153}
175154
176- impl < ' a > WriteBase32 for Bech32Writer < ' a > {
155+ impl < ' a , Ck : Checksum > WriteBase32 for Bech32Writer < ' a , Ck > {
177156 type Error = fmt:: Error ;
178157
179158 fn write_u5 ( & mut self , data : u5 ) -> fmt:: Result {
180- self . polymod_step ( data) ;
159+ self . engine . input_fe ( data) ;
181160 self . formatter . write_char ( data. to_char ( ) )
182161 }
183162}
184163
185- impl < ' a > Drop for Bech32Writer < ' a > {
164+ impl < ' a , Ck : Checksum > Drop for Bech32Writer < ' a , Ck > {
186165 fn drop ( & mut self ) {
187166 self . write_checksum ( ) . expect ( "Unhandled error writing the checksum on drop." )
188167 }
@@ -441,14 +420,31 @@ pub fn encode_to_fmt_anycase<T: AsRef<[u5]>>(
441420 data : T ,
442421 variant : Variant ,
443422) -> Result < fmt:: Result , Error > {
444- match Bech32Writer :: new ( hrp, variant, fmt) {
445- Ok ( mut writer) => {
446- Ok ( writer. write ( data. as_ref ( ) ) . and_then ( |_| {
447- // Finalize manually to avoid panic on drop if write fails
448- writer. finalize ( )
449- } ) )
423+ match variant {
424+ Variant :: Bech32 => {
425+ let res = Bech32Writer :: < Bech32 > :: new ( hrp, fmt) ;
426+ match res {
427+ Ok ( mut writer) => {
428+ Ok ( writer. write ( data. as_ref ( ) ) . and_then ( |_| {
429+ // Finalize manually to avoid panic on drop if write fails
430+ writer. finalize ( )
431+ } ) )
432+ }
433+ Err ( e) => Ok ( Err ( e) ) ,
434+ }
435+ }
436+ Variant :: Bech32m => {
437+ let res = Bech32Writer :: < Bech32m > :: new ( hrp, fmt) ;
438+ match res {
439+ Ok ( mut writer) => {
440+ Ok ( writer. write ( data. as_ref ( ) ) . and_then ( |_| {
441+ // Finalize manually to avoid panic on drop if write fails
442+ writer. finalize ( )
443+ } ) )
444+ }
445+ Err ( e) => Ok ( Err ( e) ) ,
446+ }
450447 }
451- Err ( e) => Ok ( Err ( e) ) ,
452448 }
453449}
454450
@@ -502,13 +498,6 @@ impl Variant {
502498 _ => None ,
503499 }
504500 }
505-
506- fn constant ( self ) -> u32 {
507- match self {
508- Variant :: Bech32 => BECH32_CONST ,
509- Variant :: Bech32m => BECH32M_CONST ,
510- }
511- }
512501}
513502
514503/// Encodes a bech32 payload to string.
@@ -1118,7 +1107,7 @@ mod tests {
11181107
11191108 let mut written_str = String :: new ( ) ;
11201109 {
1121- let mut writer = Bech32Writer :: new ( hrp, Variant :: Bech32 , & mut written_str) . unwrap ( ) ;
1110+ let mut writer = Bech32Writer :: < Bech32 > :: new ( hrp, & mut written_str) . unwrap ( ) ;
11221111 writer. write ( & data) . unwrap ( ) ;
11231112 writer. finalize ( ) . unwrap ( ) ;
11241113 }
@@ -1136,7 +1125,7 @@ mod tests {
11361125
11371126 let mut written_str = String :: new ( ) ;
11381127 {
1139- let mut writer = Bech32Writer :: new ( hrp, Variant :: Bech32 , & mut written_str) . unwrap ( ) ;
1128+ let mut writer = Bech32Writer :: < Bech32 > :: new ( hrp, & mut written_str) . unwrap ( ) ;
11401129 writer. write ( & data) . unwrap ( ) ;
11411130 }
11421131
@@ -1153,7 +1142,7 @@ mod tests {
11531142
11541143 let mut written_str = String :: new ( ) ;
11551144 {
1156- let mut writer = Bech32Writer :: new ( hrp, Variant :: Bech32 , & mut written_str) . unwrap ( ) ;
1145+ let mut writer = Bech32Writer :: < Bech32 > :: new ( hrp, & mut written_str) . unwrap ( ) ;
11571146 writer. write ( & data) . unwrap ( ) ;
11581147 }
11591148
@@ -1258,9 +1247,8 @@ mod tests {
12581247 let data: Vec < u8 > = FromBase32 :: from_base32 ( & data[ 1 ..] ) . expect ( "failed to convert u5s" ) ;
12591248
12601249 let mut writer = String :: new ( ) ;
1261- let mut bech32_writer =
1262- Bech32Writer :: new ( Hrp :: parse ( "BC" ) . unwrap ( ) , Variant :: Bech32 , & mut writer)
1263- . expect ( "failed to write hrp" ) ;
1250+ let mut bech32_writer = Bech32Writer :: < Bech32 > :: new ( Hrp :: parse ( "BC" ) . unwrap ( ) , & mut writer)
1251+ . expect ( "failed to write hrp" ) ;
12641252 let version = u5:: try_from ( 0 ) . unwrap ( ) ;
12651253
12661254 WriteBase32 :: write_u5 ( & mut bech32_writer, version) . expect ( "failed to write version" ) ;
0 commit comments