Skip to content

Commit 5478e2b

Browse files
committed
Add support for encoding/decoding bech32 addresses
Add support for: - Converting bytes to field elements using two extension traits (and iterator apaptors). - Checksumming an stream of field elements. - Decoding bech32 hrpstrings (as well as segwit addresses). - Encoding hrpstrings by way of an `Encoder` and a bunch of iterator adaptors.
1 parent f8ebe75 commit 5478e2b

File tree

10 files changed

+2160
-6
lines changed

10 files changed

+2160
-6
lines changed

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ use core::{fmt, mem};
3535

3636
pub use crate::primitives::checksum::Checksum;
3737
use crate::primitives::checksum::{self, PackedFe32};
38+
pub use crate::primitives::gf32::Fe32;
3839
use crate::primitives::hrp;
3940
pub use crate::primitives::hrp::Hrp;
41+
pub use crate::primitives::iter::{ByteIterExt, Fe32IterExt};
4042
pub use crate::primitives::{Bech32, Bech32m};
4143

4244
mod error;

src/primitives/checksum.rs

+62-6
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,8 @@ impl<Ck: Checksum> Engine<Ck> {
9797

9898
/// Feeds `hrp` into the checksum engine.
9999
pub fn input_hrp(&mut self, hrp: &Hrp) {
100-
for b in hrp.lowercase_byte_iter() {
101-
self.input_fe(Fe32(b >> 5));
102-
}
103-
self.input_fe(Fe32::Q);
104-
for b in hrp.lowercase_byte_iter() {
105-
self.input_fe(Fe32(b & 0x1f));
100+
for fe in HrpFe32Iter::new(hrp) {
101+
self.input_fe(fe)
106102
}
107103
}
108104

@@ -200,3 +196,63 @@ macro_rules! impl_packed_fe32 {
200196
impl_packed_fe32!(u32);
201197
impl_packed_fe32!(u64);
202198
impl_packed_fe32!(u128);
199+
200+
/// Iterator that yields the field elements that are input into a checksum algorithm for an [`Hrp`].
201+
pub struct HrpFe32Iter<'hrp> {
202+
/// `None` once the hrp high fes have been yielded.
203+
high_iter: Option<crate::hrp::LowercaseByteIter<'hrp>>,
204+
/// `None` once the hrp low fes have been yielded.
205+
low_iter: Option<crate::hrp::LowercaseByteIter<'hrp>>,
206+
}
207+
208+
impl<'hrp> HrpFe32Iter<'hrp> {
209+
/// Creates an iterator that yields the field elements of `hrp` as they are input into the
210+
/// checksum algorithm.
211+
pub fn new(hrp: &'hrp Hrp) -> Self {
212+
let high_iter = hrp.lowercase_byte_iter();
213+
let low_iter = hrp.lowercase_byte_iter();
214+
215+
Self { high_iter: Some(high_iter), low_iter: Some(low_iter) }
216+
}
217+
}
218+
219+
impl<'hrp> Iterator for HrpFe32Iter<'hrp> {
220+
type Item = Fe32;
221+
fn next(&mut self) -> Option<Fe32> {
222+
if let Some(ref mut high_iter) = &mut self.high_iter {
223+
match high_iter.next() {
224+
Some(high) => return Some(Fe32(high >> 5)),
225+
None => {
226+
self.high_iter = None;
227+
return Some(Fe32::Q);
228+
}
229+
}
230+
}
231+
if let Some(ref mut low_iter) = &mut self.low_iter {
232+
match low_iter.next() {
233+
Some(low) => return Some(Fe32(low & 0x1f)),
234+
None => self.low_iter = None,
235+
}
236+
}
237+
None
238+
}
239+
240+
fn size_hint(&self) -> (usize, Option<usize>) {
241+
let high = match &self.high_iter {
242+
Some(high_iter) => {
243+
let (min, max) = high_iter.size_hint();
244+
(min + 1, max.map(|max| max + 1)) // +1 for the extra Q
245+
}
246+
None => (0, Some(0)),
247+
};
248+
let low = match &self.low_iter {
249+
Some(low_iter) => low_iter.size_hint(),
250+
None => (0, Some(0)),
251+
};
252+
253+
let min = high.0 + 1 + low.0;
254+
let max = high.1.zip(low.1).map(|(high, low)| high + 1 + low);
255+
256+
(min, max)
257+
}
258+
}

0 commit comments

Comments
 (0)