Skip to content

Commit

Permalink
Add encoded_length functions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tcharding committed Oct 19, 2023
1 parent ba0bed9 commit 0f33396
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ pub fn encode_upper_to_writer<Ck: Checksum, W: std::io::Write>(
Ok(())
}

/// Returns the length of the bech32 string after encoding `hrp` and `data` (incl. checksum).
pub fn encoded_length<Ck: Checksum>(hrp: &Hrp, data: &[u8]) -> usize {
let iter = data.iter().copied().bytes_to_fes();
hrp.len() + 1 + iter.len() + Ck::CHECKSUM_LENGTH // +1 for separator
}

/// An error while decoding an address.
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -474,4 +480,16 @@ mod tests {
assert_eq!(hrp, Hrp::parse_unchecked("TEST"));
assert_eq!(data, DATA);
}

#[test]
fn encoded_length_works() {
let s = "test1lu08d6qejxtdg4y5r3zarvary0c5xw7kmz4lky";
let (hrp, data) = decode(s).expect("failed to decode valid address");

let encoded = encode::<Bech32m>(&hrp, &data).expect("failed to encode string");
let want = encoded.len();
let got = encoded_length::<Bech32m>(&hrp, &data);

assert_eq!(got, want);
}
}
2 changes: 2 additions & 0 deletions src/primitives/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//! In general, directly using these adaptors is not very ergonomic, and users are recommended to
//! instead use the higher-level functions at the root of this crate.
//!
//! WARNING: This module does not enforce the maximum length of an encoded bech32 string (90 chars).
//!
//! # Examples
//!
//! ```
Expand Down
2 changes: 2 additions & 0 deletions src/primitives/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
//! - `FesToBytes`: An iterator over field elements to an iterator over bytes.
//! - `Checksummed`: An iterator over field elements that appends the checksum.
//!
//! WARNING: This module does not enforce the maximum length of an encoded bech32 string (90 chars).
//!
//! # Examples
//!
//! ```
Expand Down
35 changes: 35 additions & 0 deletions src/segwit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,23 @@ pub fn encode_upper_to_writer_unchecked<W: std::io::Write>(
Ok(())
}

/// Returns the length of the bech32 string after encoding HRP, witness version and program.
///
/// # Returns
///
/// Returns the encoded length, ether as `Ok(len)` if valid or as `Err(EncodedLengthError(len))` if
/// invalid (exceeds the maximum of 90 characters as defined in [BIP-173]).
///
/// [`BIP-173`]: <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>
pub fn encoded_length(
hrp: &Hrp,
_witness_version: Fe32, // Emphasize that this is only for segwit.
witness_program: &[u8],
) -> usize {
// Ck is only for length and since they are both the same we can use either here.
crate::encoded_length::<Bech32>(hrp, witness_program) + 1 // +1 for witness version.
}

/// An error while decoding a segwit address.
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -416,4 +433,22 @@ mod tests {
let want = "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4";
assert_eq!(address, want);
}

#[test]
fn encoded_length_works() {
let addresses = vec![
"bc1q2s3rjwvam9dt2ftt4sqxqjf3twav0gdx0k0q2etxflx38c3x8tnssdmnjq",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
];

for address in addresses {
let (hrp, version, program) = decode(address).expect("failed to decode valid address");

let encoded = encode(&hrp, version, &program).expect("failed to encode string");
let want = encoded.len();
let got = encoded_length(&hrp, version, &program);

assert_eq!(got, want);
}
}
}

0 comments on commit 0f33396

Please sign in to comment.