Skip to content

Commit 1c83077

Browse files
committed
Add encoded_length functions
Currently we do not enforce the BIP-173 maximum character length for bech32 endoded strings. Add two public functions, both called `encoded_length` that calculate the length of an encoded bech32 string. Do not call the functions yet.
1 parent 6e4f6d3 commit 1c83077

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ pub fn encode_upper_to_writer<Ck: Checksum, W: std::io::Write>(
345345
Ok(())
346346
}
347347

348+
/// Returns the length of the bech32 string after encoding `hrp` and `data` (incl. checksum).
349+
pub fn encoded_length<Ck: Checksum>(hrp: Hrp, data: &[u8]) -> usize {
350+
let iter = data.iter().copied().bytes_to_fes();
351+
hrp.len() + 1 + iter.len() + Ck::CHECKSUM_LENGTH // +1 for separator
352+
}
353+
348354
/// An error while decoding a bech32 string.
349355
#[cfg(feature = "alloc")]
350356
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -390,7 +396,7 @@ impl From<UncheckedHrpstringError> for DecodeError {
390396
#[cfg(feature = "alloc")]
391397
mod tests {
392398
use super::*;
393-
use crate::Bech32;
399+
use crate::{Bech32, Bech32m};
394400

395401
// Tests below using this data, are based on the test vector (from BIP-173):
396402
// BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4: 0014751e76e8199196d454941c45d1b3a323f1433bd6
@@ -475,4 +481,16 @@ mod tests {
475481
assert_eq!(hrp, Hrp::parse_unchecked("TEST"));
476482
assert_eq!(data, DATA);
477483
}
484+
485+
#[test]
486+
fn encoded_length_works() {
487+
let s = "test1lu08d6qejxtdg4y5r3zarvary0c5xw7kmz4lky";
488+
let (hrp, data) = decode(s).expect("valid string");
489+
490+
let encoded = encode::<Bech32m>(hrp, &data).expect("valid data");
491+
let want = encoded.len();
492+
let got = encoded_length::<Bech32m>(hrp, &data);
493+
494+
assert_eq!(got, want);
495+
}
478496
}

src/primitives/encode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//! In general, directly using these adaptors is not very ergonomic, and users are recommended to
1010
//! instead use the higher-level functions at the root of this crate.
1111
//!
12+
//! WARNING: This module does not enforce the maximum length of an encoded bech32 string (90 chars).
13+
//!
1214
//! # Examples
1315
//!
1416
//! ```

src/primitives/iter.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
//! - `FesToBytes`: An iterator over field elements to an iterator over bytes.
99
//! - `Checksummed`: An iterator over field elements that appends the checksum.
1010
//!
11+
//! WARNING: This module does not enforce the maximum length of an encoded bech32 string (90 chars).
12+
//!
1113
//! # Examples
1214
//!
1315
//! ```

src/segwit.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,16 @@ pub fn encode_upper_to_writer_unchecked<W: std::io::Write>(
264264
Ok(())
265265
}
266266

267+
/// Returns the length of the bech32 string after encoding HRP, witness version and program.
268+
pub fn encoded_length(
269+
hrp: Hrp,
270+
_witness_version: Fe32, // Emphasize that this is only for segwit.
271+
witness_program: &[u8],
272+
) -> usize {
273+
// Ck is only for length and since they are both the same we can use either here.
274+
crate::encoded_length::<Bech32>(hrp, witness_program) + 1 // +1 for witness version.
275+
}
276+
267277
/// An error while decoding a segwit address.
268278
#[cfg(feature = "alloc")]
269279
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -428,4 +438,22 @@ mod tests {
428438
let want = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
429439
assert_eq!(address, want);
430440
}
441+
442+
#[test]
443+
fn encoded_length_works() {
444+
let addresses = vec![
445+
"bc1q2s3rjwvam9dt2ftt4sqxqjf3twav0gdx0k0q2etxflx38c3x8tnssdmnjq",
446+
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
447+
];
448+
449+
for address in addresses {
450+
let (hrp, version, program) = decode(address).expect("valid address");
451+
452+
let encoded = encode(hrp, version, &program).expect("valid data");
453+
let want = encoded.len();
454+
let got = encoded_length(hrp, version, &program);
455+
456+
assert_eq!(got, want);
457+
}
458+
}
431459
}

0 commit comments

Comments
 (0)