@@ -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