@@ -51,8 +51,11 @@ use alloc::{string::String, vec::Vec};
51
51
use core:: convert:: { Infallible , TryFrom } ;
52
52
use core:: { fmt, mem} ;
53
53
54
+ pub use crate :: primitives:: checksum:: Checksum ;
55
+ use crate :: primitives:: checksum:: { self , PackedFe32 } ;
54
56
use crate :: primitives:: hrp;
55
57
pub use crate :: primitives:: hrp:: Hrp ;
58
+ pub use crate :: primitives:: { Bech32 , Bech32m } ;
56
59
57
60
mod error;
58
61
pub mod primitives;
@@ -101,50 +104,26 @@ const CHECKSUM_LENGTH: usize = 6;
101
104
102
105
/// Allocationless Bech32 writer that accumulates the checksum data internally and writes them out
103
106
/// in the end.
104
- pub struct Bech32Writer < ' a > {
107
+ pub struct Bech32Writer < ' a , Ck : Checksum > {
105
108
formatter : & ' a mut dyn fmt:: Write ,
106
- chk : u32 ,
107
- variant : Variant ,
109
+ engine : checksum:: Engine < Ck > ,
108
110
}
109
111
110
- impl < ' a > Bech32Writer < ' a > {
112
+ impl < ' a , Ck : Checksum > Bech32Writer < ' a , Ck > {
111
113
/// Creates a new writer that can write a bech32 string without allocating itself.
112
114
///
113
115
/// This is a rather low-level API and doesn't check the HRP or data length for standard
114
116
/// 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) ;
121
120
122
121
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) ?;
130
123
}
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 ) ?;
142
125
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 } )
148
127
}
149
128
150
129
/// Writes out the checksum at the end.
@@ -158,31 +137,31 @@ impl<'a> Bech32Writer<'a> {
158
137
159
138
/// Calculates and writes a checksum to `self`.
160
139
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 ( ) ;
165
141
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 ;
167
145
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 ( ) ) ?;
170
149
}
171
150
172
151
Ok ( ( ) )
173
152
}
174
153
}
175
154
176
- impl < ' a > WriteBase32 for Bech32Writer < ' a > {
155
+ impl < ' a , Ck : Checksum > WriteBase32 for Bech32Writer < ' a , Ck > {
177
156
type Error = fmt:: Error ;
178
157
179
158
fn write_u5 ( & mut self , data : u5 ) -> fmt:: Result {
180
- self . polymod_step ( data) ;
159
+ self . engine . input_fe ( data) ;
181
160
self . formatter . write_char ( data. to_char ( ) )
182
161
}
183
162
}
184
163
185
- impl < ' a > Drop for Bech32Writer < ' a > {
164
+ impl < ' a , Ck : Checksum > Drop for Bech32Writer < ' a , Ck > {
186
165
fn drop ( & mut self ) {
187
166
self . write_checksum ( ) . expect ( "Unhandled error writing the checksum on drop." )
188
167
}
@@ -441,14 +420,31 @@ pub fn encode_to_fmt_anycase<T: AsRef<[u5]>>(
441
420
data : T ,
442
421
variant : Variant ,
443
422
) -> 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
+ }
450
447
}
451
- Err ( e) => Ok ( Err ( e) ) ,
452
448
}
453
449
}
454
450
@@ -502,13 +498,6 @@ impl Variant {
502
498
_ => None ,
503
499
}
504
500
}
505
-
506
- fn constant ( self ) -> u32 {
507
- match self {
508
- Variant :: Bech32 => BECH32_CONST ,
509
- Variant :: Bech32m => BECH32M_CONST ,
510
- }
511
- }
512
501
}
513
502
514
503
/// Encodes a bech32 payload to string.
@@ -1118,7 +1107,7 @@ mod tests {
1118
1107
1119
1108
let mut written_str = String :: new ( ) ;
1120
1109
{
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 ( ) ;
1122
1111
writer. write ( & data) . unwrap ( ) ;
1123
1112
writer. finalize ( ) . unwrap ( ) ;
1124
1113
}
@@ -1136,7 +1125,7 @@ mod tests {
1136
1125
1137
1126
let mut written_str = String :: new ( ) ;
1138
1127
{
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 ( ) ;
1140
1129
writer. write ( & data) . unwrap ( ) ;
1141
1130
}
1142
1131
@@ -1153,7 +1142,7 @@ mod tests {
1153
1142
1154
1143
let mut written_str = String :: new ( ) ;
1155
1144
{
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 ( ) ;
1157
1146
writer. write ( & data) . unwrap ( ) ;
1158
1147
}
1159
1148
@@ -1258,9 +1247,8 @@ mod tests {
1258
1247
let data: Vec < u8 > = FromBase32 :: from_base32 ( & data[ 1 ..] ) . expect ( "failed to convert u5s" ) ;
1259
1248
1260
1249
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" ) ;
1264
1252
let version = u5:: try_from ( 0 ) . unwrap ( ) ;
1265
1253
1266
1254
WriteBase32 :: write_u5 ( & mut bech32_writer, version) . expect ( "failed to write version" ) ;
0 commit comments