bech32/
segwit.rs

1// SPDX-License-Identifier: MIT
2
3//! Segregated Witness API - enables typical usage for encoding and decoding segwit addresses.
4//!
5//! [BIP-173] and [BIP-350] contain some complexity. This module aims to allow you to create modern
6//! Bitcoin addresses correctly and easily without intimate knowledge of the BIPs. However, if you
7//! do posses such knowledge and are doing unusual things you may prefer to use the `primitives`
8//! submodules directly.
9//!
10//! # Examples
11//!
12//! ```
13//! # #[cfg(feature = "alloc")] {
14//! use bech32::{hrp, segwit, Fe32, Hrp};
15//!
16//! let witness_prog = [
17//!     0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4,
18//!     0x54, 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23,
19//!     0xf1, 0x43, 0x3b, 0xd6,
20//! ];
21//!
22//! // Encode a taproot address suitable for use on mainnet.
23//! let _ = segwit::encode_v1(hrp::BC, &witness_prog);
24//!
25//! // Encode a segwit v0 address suitable for use on testnet.
26//! let _ = segwit::encode_v0(hrp::TB, &witness_prog);
27//!
28//! // If you have the witness version already you can use:
29//! # let witness_version = segwit::VERSION_0;
30//! let _ = segwit::encode(hrp::BC, witness_version, &witness_prog);
31//!
32//! // Decode a Bitcoin bech32 segwit address.
33//! let address = "bc1q2s3rjwvam9dt2ftt4sqxqjf3twav0gdx0k0q2etxflx38c3x8tnssdmnjq";
34//! let (hrp, witness_version, witness_program) = segwit::decode(address).expect("failed to decode address");
35//! # }
36//! ```
37//!
38//! [BIP-173]: <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>
39//! [BIP-350]: <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>
40//! [`bip_173_test_vectors.rs`]: <https://github.com/rust-bitcoin/rust-bech32/blob/master/tests/bip_173_test_vectors.rs>
41//! [`bip_350_test_vectors.rs`]: <https://github.com/rust-bitcoin/rust-bech32/blob/master/tests/bip_350_test_vectors.rs>
42
43#[cfg(all(feature = "alloc", not(feature = "std"), not(test)))]
44use alloc::{string::String, vec::Vec};
45use core::fmt;
46
47use crate::error::write_err;
48use crate::primitives::decode::SegwitCodeLengthError;
49#[cfg(feature = "alloc")]
50use crate::primitives::decode::{SegwitHrpstring, SegwitHrpstringError};
51use crate::primitives::gf32::Fe32;
52use crate::primitives::hrp::Hrp;
53use crate::primitives::iter::{ByteIterExt, Fe32IterExt};
54#[cfg(feature = "alloc")]
55use crate::primitives::segwit;
56use crate::primitives::segwit::{
57    InvalidWitnessVersionError, WitnessLengthError, MAX_STRING_LENGTH,
58};
59use crate::primitives::{Bech32, Bech32m};
60
61#[rustfmt::skip]                // Keep public re-exports separate.
62#[doc(inline)]
63pub use {
64    crate::primitives::segwit::{VERSION_0, VERSION_1},
65};
66
67/// Decodes a segwit address.
68///
69/// # Returns
70///
71/// The HRP, the witness version, and a guaranteed valid length witness program.
72///
73/// # Examples
74///
75/// ```
76/// use bech32::segwit;
77/// let address = "bc1py3m7vwnghyne9gnvcjw82j7gqt2rafgdmlmwmqnn3hvcmdm09rjqcgrtxs";
78/// let (_hrp, _witness_version, _witness_program) = segwit::decode(address).expect("failed to decode address");
79/// ```
80#[cfg(feature = "alloc")]
81#[inline]
82pub fn decode(s: &str) -> Result<(Hrp, Fe32, Vec<u8>), DecodeError> {
83    let segwit = SegwitHrpstring::new(s)?;
84    Ok((segwit.hrp(), segwit.witness_version(), segwit.byte_iter().collect::<Vec<u8>>()))
85}
86
87/// Encodes a segwit address.
88///
89/// Does validity checks on the `witness_version`, length checks on the `witness_program`, and
90/// checks the total encoded string length.
91///
92/// As specified by [BIP-350] we use the [`Bech32m`] checksum algorithm for witness versions 1 and
93/// above, and for witness version 0 we use the original ([BIP-173]) [`Bech32`] checksum
94/// algorithm.
95///
96/// See also [`encode_v0`] or [`encode_v1`].
97///
98/// [`Bech32`]: crate::primitives::Bech32
99/// [`Bech32m`]: crate::primitives::Bech32m
100/// [BIP-173]: <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>
101/// [BIP-350]: <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>
102#[cfg(feature = "alloc")]
103#[inline]
104pub fn encode(
105    hrp: Hrp,
106    witness_version: Fe32,
107    witness_program: &[u8],
108) -> Result<String, EncodeError> {
109    segwit::validate_witness_version(witness_version)?;
110    segwit::validate_witness_program_length(witness_program.len(), witness_version)?;
111
112    let _ = encoded_length(hrp, witness_version, witness_program)?;
113
114    let mut buf = String::new();
115    encode_to_fmt_unchecked(&mut buf, hrp, witness_version, witness_program)?;
116    Ok(buf)
117}
118
119/// Encodes a segwit version 0 address.
120///
121/// Does validity checks on the `witness_version`, length checks on the `witness_program`, and
122/// checks the total encoded string length.
123#[cfg(feature = "alloc")]
124#[inline]
125pub fn encode_v0(hrp: Hrp, witness_program: &[u8]) -> Result<String, EncodeError> {
126    encode(hrp, VERSION_0, witness_program)
127}
128
129/// Encodes a segwit version 1 address.
130///
131/// Does validity checks on the `witness_version`, length checks on the `witness_program`, and
132/// checks the total encoded string length.
133#[cfg(feature = "alloc")]
134#[inline]
135pub fn encode_v1(hrp: Hrp, witness_program: &[u8]) -> Result<String, EncodeError> {
136    encode(hrp, VERSION_1, witness_program)
137}
138
139/// Encodes a segwit address to a writer ([`fmt::Write`]) using lowercase characters.
140///
141/// There are no guarantees that the written string is a valid segwit address unless all the
142/// parameters are valid. See the body of `encode()` to see the validity checks required.
143#[inline]
144pub fn encode_to_fmt_unchecked<W: fmt::Write>(
145    fmt: &mut W,
146    hrp: Hrp,
147    witness_version: Fe32,
148    witness_program: &[u8],
149) -> fmt::Result {
150    encode_lower_to_fmt_unchecked(fmt, hrp, witness_version, witness_program)
151}
152
153/// Encodes a segwit address to a writer ([`fmt::Write`]) using lowercase characters.
154///
155/// There are no guarantees that the written string is a valid segwit address unless all the
156/// parameters are valid. See the body of `encode()` to see the validity checks required.
157pub fn encode_lower_to_fmt_unchecked<W: fmt::Write>(
158    fmt: &mut W,
159    hrp: Hrp,
160    witness_version: Fe32,
161    witness_program: &[u8],
162) -> fmt::Result {
163    let mut buf = [0u8; MAX_STRING_LENGTH];
164    let mut pos = 0;
165
166    let iter = witness_program.iter().copied().bytes_to_fes();
167    match witness_version {
168        VERSION_0 => {
169            let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
170            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
171                *dst = src;
172                pos += 1;
173            });
174        }
175        version => {
176            let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
177            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
178                *dst = src;
179                pos += 1;
180            });
181        }
182    }
183
184    let s = core::str::from_utf8(&buf[..pos]).expect("we only write ASCII");
185    fmt.write_str(s)?;
186
187    Ok(())
188}
189
190/// Encodes a segwit address to a writer ([`fmt::Write`]) using uppercase characters.
191///
192/// This is provided for use when creating QR codes.
193///
194/// There are no guarantees that the written string is a valid segwit address unless all the
195/// parameters are valid. See the body of `encode()` to see the validity checks required.
196#[inline]
197pub fn encode_upper_to_fmt_unchecked<W: fmt::Write>(
198    fmt: &mut W,
199    hrp: Hrp,
200    witness_version: Fe32,
201    witness_program: &[u8],
202) -> fmt::Result {
203    let mut buf = [0u8; MAX_STRING_LENGTH];
204    let mut pos = 0;
205
206    let iter = witness_program.iter().copied().bytes_to_fes();
207    match witness_version {
208        VERSION_0 => {
209            let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
210            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
211                *dst = src.to_ascii_uppercase();
212                pos += 1;
213            });
214        }
215        version => {
216            let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
217            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
218                *dst = src.to_ascii_uppercase();
219                pos += 1;
220            });
221        }
222    }
223
224    let s = core::str::from_utf8(&buf[..pos]).expect("we only write ASCII");
225    fmt.write_str(s)?;
226
227    Ok(())
228}
229
230/// Encodes a segwit address to a writer ([`io::Write`]) using lowercase characters.
231///
232/// There are no guarantees that the written string is a valid segwit address unless all the
233/// parameters are valid. See the body of `encode()` to see the validity checks required.
234///
235/// [`io::Write`]: std::io::Write
236#[cfg(feature = "std")]
237#[inline]
238pub fn encode_to_writer_unchecked<W: std::io::Write>(
239    w: &mut W,
240    hrp: Hrp,
241    witness_version: Fe32,
242    witness_program: &[u8],
243) -> std::io::Result<()> {
244    encode_lower_to_writer_unchecked(w, hrp, witness_version, witness_program)
245}
246
247/// Encodes a segwit address to a writer ([`io::Write`]) using lowercase characters.
248///
249/// There are no guarantees that the written string is a valid segwit address unless all the
250/// parameters are valid. See the body of `encode()` to see the validity checks required.
251///
252/// [`io::Write`]: std::io::Write
253#[cfg(feature = "std")]
254#[inline]
255pub fn encode_lower_to_writer_unchecked<W: std::io::Write>(
256    w: &mut W,
257    hrp: Hrp,
258    witness_version: Fe32,
259    witness_program: &[u8],
260) -> std::io::Result<()> {
261    let mut buf = [0u8; MAX_STRING_LENGTH];
262    let mut pos = 0;
263
264    let iter = witness_program.iter().copied().bytes_to_fes();
265    match witness_version {
266        VERSION_0 => {
267            let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
268            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
269                *dst = src;
270                pos += 1;
271            });
272        }
273        version => {
274            let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
275            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
276                *dst = src;
277                pos += 1;
278            });
279        }
280    }
281
282    w.write_all(&buf[..pos])?;
283
284    Ok(())
285}
286
287/// Encodes a segwit address to a [`io::Write`] writer using uppercase characters.
288///
289/// This is provided for use when creating QR codes.
290///
291/// There are no guarantees that the written string is a valid segwit address unless all the
292/// parameters are valid. See the body of `encode()` to see the validity checks required.
293///
294/// [`io::Write`]: std::io::Write
295#[cfg(feature = "std")]
296#[inline]
297pub fn encode_upper_to_writer_unchecked<W: std::io::Write>(
298    w: &mut W,
299    hrp: Hrp,
300    witness_version: Fe32,
301    witness_program: &[u8],
302) -> std::io::Result<()> {
303    let mut buf = [0u8; MAX_STRING_LENGTH];
304    let mut pos = 0;
305
306    let iter = witness_program.iter().copied().bytes_to_fes();
307    match witness_version {
308        VERSION_0 => {
309            let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
310            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
311                *dst = src.to_ascii_uppercase();
312                pos += 1;
313            });
314        }
315        version => {
316            let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
317            buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
318                *dst = src.to_ascii_uppercase();
319                pos += 1;
320            });
321        }
322    }
323
324    w.write_all(&buf[..pos])?;
325
326    Ok(())
327}
328
329/// Returns the length of the address after encoding HRP, witness version and program.
330///
331/// # Returns
332///
333/// `Ok(address_length)` if the encoded address length is less than or equal to 90. Otherwise
334/// returns a [`SegwitCodeLengthError`] containing the encoded address length.
335pub fn encoded_length(
336    hrp: Hrp,
337    _witness_version: Fe32, // Emphasize that this is only for segwit.
338    witness_program: &[u8],
339) -> Result<usize, SegwitCodeLengthError> {
340    // Ck is only for length and since they are both the same we can use either here.
341    let len = crate::encoded_length::<Bech32>(hrp, witness_program).map(|len| len + 1)?; // +1 for witness version.
342
343    if len > MAX_STRING_LENGTH {
344        Err(SegwitCodeLengthError(len))
345    } else {
346        Ok(len)
347    }
348}
349
350/// An error while decoding a segwit address.
351#[cfg(feature = "alloc")]
352#[derive(Debug, Clone, PartialEq, Eq)]
353#[non_exhaustive]
354pub struct DecodeError(pub SegwitHrpstringError);
355
356#[cfg(feature = "alloc")]
357impl fmt::Display for DecodeError {
358    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
359        write_err!(f, "decoding segwit address failed"; self.0)
360    }
361}
362
363#[cfg(feature = "std")]
364impl std::error::Error for DecodeError {
365    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
366}
367
368#[cfg(feature = "alloc")]
369impl From<SegwitHrpstringError> for DecodeError {
370    #[inline]
371    fn from(e: SegwitHrpstringError) -> Self { Self(e) }
372}
373
374/// An error while constructing a [`SegwitHrpstring`] type.
375#[derive(Debug, Clone, PartialEq, Eq)]
376#[non_exhaustive]
377#[cfg(feature = "alloc")]
378pub enum EncodeError {
379    /// Invalid witness version (must be 0-16 inclusive).
380    WitnessVersion(InvalidWitnessVersionError),
381    /// Invalid witness length.
382    WitnessLength(WitnessLengthError),
383    /// Encoding HRP, witver, and program into a bech32 string exceeds maximum allowed.
384    TooLong(SegwitCodeLengthError),
385    /// Writing to formatter failed.
386    Fmt(fmt::Error),
387}
388
389#[cfg(feature = "alloc")]
390impl fmt::Display for EncodeError {
391    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392        use EncodeError::*;
393
394        match *self {
395            WitnessVersion(ref e) => write_err!(f, "witness version"; e),
396            WitnessLength(ref e) => write_err!(f, "witness length"; e),
397            TooLong(ref e) => write_err!(f, "encode error"; e),
398            Fmt(ref e) => write_err!(f, "writing to formatter failed"; e),
399        }
400    }
401}
402
403#[cfg(feature = "std")]
404#[cfg(feature = "alloc")]
405impl std::error::Error for EncodeError {
406    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
407        use EncodeError::*;
408
409        match *self {
410            WitnessVersion(ref e) => Some(e),
411            WitnessLength(ref e) => Some(e),
412            TooLong(ref e) => Some(e),
413            Fmt(ref e) => Some(e),
414        }
415    }
416}
417
418#[cfg(feature = "alloc")]
419impl From<InvalidWitnessVersionError> for EncodeError {
420    #[inline]
421    fn from(e: InvalidWitnessVersionError) -> Self { Self::WitnessVersion(e) }
422}
423
424#[cfg(feature = "alloc")]
425impl From<WitnessLengthError> for EncodeError {
426    #[inline]
427    fn from(e: WitnessLengthError) -> Self { Self::WitnessLength(e) }
428}
429
430#[cfg(feature = "alloc")]
431impl From<SegwitCodeLengthError> for EncodeError {
432    #[inline]
433    fn from(e: SegwitCodeLengthError) -> Self { Self::TooLong(e) }
434}
435
436#[cfg(feature = "alloc")]
437impl From<fmt::Error> for EncodeError {
438    #[inline]
439    fn from(e: fmt::Error) -> Self { Self::Fmt(e) }
440}
441
442#[cfg(all(test, feature = "alloc"))]
443mod tests {
444    use super::*;
445    use crate::primitives::decode::{SegwitCodeLengthError, SegwitHrpstringError};
446    use crate::primitives::hrp;
447
448    #[test]
449    // Just shows we handle both v0 and v1 addresses, for complete test
450    // coverage see primitives submodules and test vectors.
451    fn roundtrip_valid_mainnet_addresses() {
452        // A few recent addresses from mainnet (Block 801266).
453        let addresses = vec![
454            "bc1q2s3rjwvam9dt2ftt4sqxqjf3twav0gdx0k0q2etxflx38c3x8tnssdmnjq", // Segwit v0
455            "bc1py3m7vwnghyne9gnvcjw82j7gqt2rafgdmlmwmqnn3hvcmdm09rjqcgrtxs", // Segwit v1
456        ];
457
458        for address in addresses {
459            let (hrp, version, program) = decode(address).expect("failed to decode valid address");
460            let encoded = encode(hrp, version, &program).expect("failed to encode address");
461            assert_eq!(encoded, address);
462        }
463    }
464
465    fn witness_program() -> [u8; 20] {
466        [
467            0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c, 0x45, 0xd1, 0xb3,
468            0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
469        ]
470    }
471
472    #[test]
473    fn encode_lower_to_fmt() {
474        let program = witness_program();
475        let mut address = String::new();
476        encode_to_fmt_unchecked(&mut address, hrp::BC, VERSION_0, &program)
477            .expect("failed to encode address to QR code");
478
479        let want = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
480        assert_eq!(address, want);
481    }
482
483    #[test]
484    fn encode_upper_to_fmt() {
485        let program = witness_program();
486        let mut address = String::new();
487        encode_upper_to_fmt_unchecked(&mut address, hrp::BC, VERSION_0, &program)
488            .expect("failed to encode address to QR code");
489
490        let want = "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4";
491        assert_eq!(address, want);
492    }
493
494    #[test]
495    #[cfg(feature = "std")]
496    fn encode_lower_to_writer() {
497        let program = witness_program();
498        let mut buf = Vec::new();
499        encode_lower_to_writer_unchecked(&mut buf, hrp::BC, VERSION_0, &program)
500            .expect("failed to encode");
501
502        let address = std::str::from_utf8(&buf).expect("ascii is valid utf8");
503        let want = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
504        assert_eq!(address, want);
505    }
506
507    #[test]
508    #[cfg(feature = "std")]
509    fn encode_upper_to_writer() {
510        let program = witness_program();
511        let mut buf = Vec::new();
512        encode_upper_to_writer_unchecked(&mut buf, hrp::BC, VERSION_0, &program)
513            .expect("failed to encode");
514
515        let address = std::str::from_utf8(&buf).expect("ascii is valid utf8");
516        let want = "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4";
517        assert_eq!(address, want);
518    }
519
520    #[test]
521    #[cfg(feature = "std")]
522    fn encode_lower_to_writer_including_lowecaseing_hrp() {
523        let program = witness_program();
524        let mut buf = Vec::new();
525        let hrp = Hrp::parse_unchecked("BC");
526        encode_lower_to_writer_unchecked(&mut buf, hrp, VERSION_0, &program)
527            .expect("failed to encode");
528
529        let address = std::str::from_utf8(&buf).expect("ascii is valid utf8");
530        let want = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
531        assert_eq!(address, want);
532    }
533
534    #[test]
535    fn encoded_length_works() {
536        let addresses = vec![
537            "bc1q2s3rjwvam9dt2ftt4sqxqjf3twav0gdx0k0q2etxflx38c3x8tnssdmnjq",
538            "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
539        ];
540
541        for address in addresses {
542            let (hrp, version, program) = decode(address).expect("valid address");
543
544            let encoded = encode(hrp, version, &program).expect("valid data");
545            let want = encoded.len();
546            let got = encoded_length(hrp, version, &program).expect("encoded length");
547
548            assert_eq!(got, want);
549        }
550    }
551
552    #[test]
553    fn can_encode_maximum_length_address() {
554        let program = [0_u8; 40]; // Maximum witness program length.
555        let hrp = Hrp::parse_unchecked("anhrpthatis18chars");
556        let addr = encode(hrp, VERSION_1, &program).expect("valid data");
557        assert_eq!(addr.len(), MAX_STRING_LENGTH);
558    }
559
560    #[test]
561    fn can_not_encode_address_too_long() {
562        let tcs = vec![
563            ("anhrpthatis19charsx", 91),
564            ("anhrpthatisthemaximumallowedlengthofeightythreebytesxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 155)
565        ];
566
567        for (hrp, len) in tcs {
568            let program = [0_u8; 40]; // Maximum witness program length.
569            let hrp = Hrp::parse_unchecked(hrp);
570            let err = encode(hrp, VERSION_1, &program).unwrap_err();
571            assert_eq!(err, EncodeError::TooLong(SegwitCodeLengthError(len)));
572        }
573    }
574
575    #[test]
576    fn can_decode_maximum_length_address() {
577        let address = "anhrpthatisnineteen1pqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqghfyyfz";
578        assert_eq!(address.len(), MAX_STRING_LENGTH);
579
580        assert!(decode(address).is_ok());
581    }
582
583    #[test]
584    fn can_not_decode_address_too_long() {
585        let address = "anhrpthatistwentycha1pqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqfrwjz";
586        assert_eq!(address.len(), MAX_STRING_LENGTH + 1);
587
588        assert_eq!(decode(address).unwrap_err(), DecodeError(SegwitHrpstringError::TooLong(91)));
589    }
590}