@@ -117,8 +117,8 @@ pub struct UncheckedHrpstring<'s> {
117
117
hrp : Hrp ,
118
118
/// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
119
119
///
120
- /// Contains the checksum if one was present in the parsed string .
121
- data : & ' s [ u8 ] ,
120
+ /// The characters after the separator i.e., the "data part" defined by BIP-173 .
121
+ data_part_ascii : & ' s [ u8 ] ,
122
122
/// The length of the parsed hrpstring.
123
123
hrpstring_length : usize ,
124
124
}
@@ -130,11 +130,11 @@ impl<'s> UncheckedHrpstring<'s> {
130
130
#[ inline]
131
131
pub fn new ( s : & ' s str ) -> Result < Self , UncheckedHrpstringError > {
132
132
let sep_pos = check_characters ( s) ?;
133
- let ( hrp, data ) = s. split_at ( sep_pos) ;
133
+ let ( hrp, rest ) = s. split_at ( sep_pos) ;
134
134
135
135
let ret = UncheckedHrpstring {
136
136
hrp : Hrp :: parse ( hrp) ?,
137
- data : data [ 1 ..] . as_bytes ( ) , // Skip the separator.
137
+ data_part_ascii : rest [ 1 ..] . as_bytes ( ) , // Skip the separator.
138
138
hrpstring_length : s. len ( ) ,
139
139
} ;
140
140
@@ -145,6 +145,85 @@ impl<'s> UncheckedHrpstring<'s> {
145
145
#[ inline]
146
146
pub fn hrp ( & self ) -> Hrp { self . hrp }
147
147
148
+ /// Returns the data part as ASCII bytes i.e., everything after the separator '1'.
149
+ ///
150
+ /// The byte values are guaranteed to be valid bech32 characters. Includes the checksum
151
+ /// if one was present in the parsed string.
152
+ ///
153
+ /// # Examples
154
+ ///
155
+ /// ```
156
+ /// use bech32::primitives::decode::UncheckedHrpstring;
157
+ ///
158
+ /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
159
+ /// let ascii = "qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
160
+ ///
161
+ /// let unchecked = UncheckedHrpstring::new(&addr).unwrap();
162
+ /// assert!(unchecked.data_part_ascii().iter().eq(ascii.as_bytes().iter()))
163
+ /// ```
164
+ #[ inline]
165
+ pub fn data_part_ascii ( & self ) -> & [ u8 ] { self . data_part_ascii }
166
+
167
+ /// Attempts to remove the first byte of the data part, treating it as a witness version.
168
+ ///
169
+ /// If [`Self::witness_version`] succeeds this function removes the first character (witness
170
+ /// version byte) from the internal ASCII data part buffer. Future calls to
171
+ /// [`Self::data_part_ascii`] will no longer include it.
172
+ ///
173
+ /// # Examples
174
+ ///
175
+ /// ```
176
+ /// use bech32::{primitives::decode::UncheckedHrpstring, Fe32};
177
+ ///
178
+ /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
179
+ /// let ascii = "ar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
180
+ ///
181
+ /// let mut unchecked = UncheckedHrpstring::new(&addr).unwrap();
182
+ /// let witness_version = unchecked.remove_witness_version().unwrap();
183
+ /// assert_eq!(witness_version, Fe32::Q);
184
+ /// assert!(unchecked.data_part_ascii().iter().eq(ascii.as_bytes().iter()))
185
+ /// ```
186
+ #[ inline]
187
+ pub fn remove_witness_version ( & mut self ) -> Option < Fe32 > {
188
+ self . witness_version ( ) . map ( |witver| {
189
+ self . data_part_ascii = & self . data_part_ascii [ 1 ..] ; // Remove the witness version byte.
190
+ witver
191
+ } )
192
+ }
193
+
194
+ /// Returns the segwit witness version if there is one.
195
+ ///
196
+ /// Attempts to convert the first character of the data part to a witness version. If this
197
+ /// succeeds, and it is a valid version (0..16 inclusive) we return it, otherwise `None`.
198
+ ///
199
+ /// This function makes no guarantees on the validity of the checksum.
200
+ ///
201
+ /// # Examples
202
+ ///
203
+ /// ```
204
+ /// use bech32::{primitives::decode::UncheckedHrpstring, Fe32};
205
+ ///
206
+ /// // Note the invalid checksum!
207
+ /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzffffff";
208
+ ///
209
+ /// let unchecked = UncheckedHrpstring::new(&addr).unwrap();
210
+ /// assert_eq!(unchecked.witness_version(), Some(Fe32::Q));
211
+ /// ```
212
+ #[ inline]
213
+ pub fn witness_version ( & self ) -> Option < Fe32 > {
214
+ let data_part = self . data_part_ascii ( ) ;
215
+ if data_part. is_empty ( ) {
216
+ return None ;
217
+ }
218
+
219
+ // unwrap ok because we know we gave valid bech32 characters.
220
+ let witness_version = Fe32 :: from_char ( data_part[ 0 ] . into ( ) ) . unwrap ( ) ;
221
+ if witness_version. to_u8 ( ) > 16 {
222
+ return None ;
223
+ }
224
+ Some ( witness_version)
225
+ }
226
+
148
227
/// Validates that data has a valid checksum for the `Ck` algorithm and returns a [`CheckedHrpstring`].
149
228
#[ inline]
150
229
pub fn validate_and_remove_checksum < Ck : Checksum > (
@@ -183,15 +262,15 @@ impl<'s> UncheckedHrpstring<'s> {
183
262
return Ok ( ( ) ) ;
184
263
}
185
264
186
- if self . data . len ( ) < Ck :: CHECKSUM_LENGTH {
265
+ if self . data_part_ascii . len ( ) < Ck :: CHECKSUM_LENGTH {
187
266
return Err ( InvalidLength ) ;
188
267
}
189
268
190
269
let mut checksum_eng = checksum:: Engine :: < Ck > :: new ( ) ;
191
270
checksum_eng. input_hrp ( self . hrp ( ) ) ;
192
271
193
272
// Unwrap ok since we checked all characters in our constructor.
194
- for fe in self . data . iter ( ) . map ( |& b| Fe32 :: from_char_unchecked ( b) ) {
273
+ for fe in self . data_part_ascii . iter ( ) . map ( |& b| Fe32 :: from_char_unchecked ( b) ) {
195
274
checksum_eng. input_fe ( fe) ;
196
275
}
197
276
@@ -213,20 +292,20 @@ impl<'s> UncheckedHrpstring<'s> {
213
292
/// May panic if data is not valid.
214
293
#[ inline]
215
294
pub fn remove_checksum < Ck : Checksum > ( self ) -> CheckedHrpstring < ' s > {
216
- let data_len = self . data . len ( ) - Ck :: CHECKSUM_LENGTH ;
295
+ let end = self . data_part_ascii . len ( ) - Ck :: CHECKSUM_LENGTH ;
217
296
218
297
CheckedHrpstring {
219
298
hrp : self . hrp ( ) ,
220
- data : & self . data [ ..data_len ] ,
299
+ ascii : & self . data_part_ascii [ ..end ] ,
221
300
hrpstring_length : self . hrpstring_length ,
222
301
}
223
302
}
224
303
}
225
304
226
305
/// An HRP string that has been parsed and had the checksum validated.
227
306
///
228
- /// This type does not treat the first byte of the data in any special way i.e., as the witness
229
- /// version byte. If you are parsing Bitcoin segwit addresses you likely want to use [`SegwitHrpstring`].
307
+ /// This type does not treat the first byte of the data part in any special way i.e., as the witness
308
+ /// version byte. If you are parsing Bitcoin segwit addresses consider using [`SegwitHrpstring`].
230
309
///
231
310
/// > We first describe the general checksummed base32 format called Bech32 and then
232
311
/// > define Segregated Witness addresses using it.
@@ -250,9 +329,10 @@ impl<'s> UncheckedHrpstring<'s> {
250
329
pub struct CheckedHrpstring < ' s > {
251
330
/// The human-readable part, guaranteed to be lowercase ASCII characters.
252
331
hrp : Hrp ,
253
- /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters,
254
- /// with the checksum removed.
255
- data : & ' s [ u8 ] ,
332
+ /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
333
+ ///
334
+ /// The characters after the '1' separator and the before the checksum.
335
+ ascii : & ' s [ u8 ] ,
256
336
/// The length of the parsed hrpstring.
257
337
hrpstring_length : usize , // Guaranteed to be <= CK::CODE_LENGTH
258
338
}
@@ -274,19 +354,38 @@ impl<'s> CheckedHrpstring<'s> {
274
354
#[ inline]
275
355
pub fn hrp ( & self ) -> Hrp { self . hrp }
276
356
357
+ /// Returns a partial slice of the data part, as ASCII bytes, everything after the separator '1'
358
+ /// before the checksum.
359
+ ///
360
+ /// The byte values are guaranteed to be valid bech32 characters.
361
+ ///
362
+ /// # Examples
363
+ ///
364
+ /// ```
365
+ /// use bech32::{Bech32, primitives::decode::CheckedHrpstring};
366
+ ///
367
+ /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
368
+ /// let ascii = "qar0srrr7xfkvy5l643lydnw9re59gtzz";
369
+ ///
370
+ /// let checked = CheckedHrpstring::new::<Bech32>(&addr).unwrap();
371
+ /// assert!(checked.data_part_ascii_no_checksum().iter().eq(ascii.as_bytes().iter()))
372
+ /// ```
373
+ #[ inline]
374
+ pub fn data_part_ascii_no_checksum ( & self ) -> & [ u8 ] { self . ascii }
375
+
277
376
/// Returns an iterator that yields the data part of the parsed bech32 encoded string.
278
377
///
279
378
/// Converts the ASCII bytes representing field elements to the respective field elements, then
280
379
/// converts the stream of field elements to a stream of bytes.
281
380
#[ inline]
282
381
pub fn byte_iter ( & self ) -> ByteIter {
283
- ByteIter { iter : AsciiToFe32Iter { iter : self . data . iter ( ) . copied ( ) } . fes_to_bytes ( ) }
382
+ ByteIter { iter : AsciiToFe32Iter { iter : self . ascii . iter ( ) . copied ( ) } . fes_to_bytes ( ) }
284
383
}
285
384
286
385
/// Converts this type to a [`SegwitHrpstring`] after validating the witness and HRP.
287
386
#[ inline]
288
387
pub fn validate_segwit ( mut self ) -> Result < SegwitHrpstring < ' s > , SegwitHrpstringError > {
289
- if self . data . is_empty ( ) {
388
+ if self . ascii . is_empty ( ) {
290
389
return Err ( SegwitHrpstringError :: NoData ) ;
291
390
}
292
391
@@ -295,28 +394,28 @@ impl<'s> CheckedHrpstring<'s> {
295
394
}
296
395
297
396
// Unwrap ok since check_characters checked the bech32-ness of this char.
298
- let witness_version = Fe32 :: from_char ( self . data [ 0 ] . into ( ) ) . unwrap ( ) ;
299
- self . data = & self . data [ 1 ..] ; // Remove the witness version byte from data .
397
+ let witness_version = Fe32 :: from_char ( self . ascii [ 0 ] . into ( ) ) . unwrap ( ) ;
398
+ self . ascii = & self . ascii [ 1 ..] ; // Remove the witness version byte.
300
399
301
400
self . validate_padding ( ) ?;
302
401
self . validate_witness_program_length ( witness_version) ?;
303
402
304
- Ok ( SegwitHrpstring { hrp : self . hrp ( ) , witness_version, data : self . data } )
403
+ Ok ( SegwitHrpstring { hrp : self . hrp ( ) , witness_version, ascii : self . ascii } )
305
404
}
306
405
307
406
/// Validates the segwit padding rules.
308
407
///
309
- /// Must be called after the witness version byte is removed from the data.
408
+ /// Must be called after the witness version byte is removed from the data part .
310
409
///
311
410
/// From BIP-173:
312
411
/// > Re-arrange those bits into groups of 8 bits. Any incomplete group at the
313
412
/// > end MUST be 4 bits or less, MUST be all zeroes, and is discarded.
314
413
fn validate_padding ( & self ) -> Result < ( ) , PaddingError > {
315
- if self . data . is_empty ( ) {
414
+ if self . ascii . is_empty ( ) {
316
415
return Ok ( ( ) ) ; // Empty data implies correct padding.
317
416
}
318
417
319
- let fe_iter = AsciiToFe32Iter { iter : self . data . iter ( ) . copied ( ) } ;
418
+ let fe_iter = AsciiToFe32Iter { iter : self . ascii . iter ( ) . copied ( ) } ;
320
419
let padding_len = fe_iter. len ( ) * 5 % 8 ;
321
420
322
421
if padding_len > 4 {
@@ -343,7 +442,7 @@ impl<'s> CheckedHrpstring<'s> {
343
442
344
443
/// Validates the segwit witness length rules.
345
444
///
346
- /// Must be called after the witness version byte is removed from the data.
445
+ /// Must be called after the witness version byte is removed from the data part .
347
446
fn validate_witness_program_length (
348
447
& self ,
349
448
witness_version : Fe32 ,
@@ -372,11 +471,12 @@ impl<'s> CheckedHrpstring<'s> {
372
471
pub struct SegwitHrpstring < ' s > {
373
472
/// The human-readable part, valid for segwit addresses.
374
473
hrp : Hrp ,
375
- /// The first byte of the parsed data.
474
+ /// The first byte of the parsed data part .
376
475
witness_version : Fe32 ,
377
- /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters,
378
- /// with the witness version and checksum removed.
379
- data : & ' s [ u8 ] ,
476
+ /// This is ASCII byte values of the parsed string, guaranteed to be valid bech32 characters.
477
+ ///
478
+ /// The characters after the witness version and before the checksum.
479
+ ascii : & ' s [ u8 ] ,
380
480
}
381
481
382
482
impl < ' s > SegwitHrpstring < ' s > {
@@ -396,12 +496,14 @@ impl<'s> SegwitHrpstring<'s> {
396
496
397
497
let unchecked = UncheckedHrpstring :: new ( s) ?;
398
498
399
- if unchecked. data . is_empty ( ) {
499
+ let data_part = unchecked. data_part_ascii ( ) ;
500
+
501
+ if data_part. is_empty ( ) {
400
502
return Err ( SegwitHrpstringError :: NoData ) ;
401
503
}
402
504
403
505
// Unwrap ok since check_characters (in `Self::new`) checked the bech32-ness of this char.
404
- let witness_version = Fe32 :: from_char ( unchecked . data [ 0 ] . into ( ) ) . unwrap ( ) ;
506
+ let witness_version = Fe32 :: from_char ( data_part [ 0 ] . into ( ) ) . unwrap ( ) ;
405
507
if witness_version. to_u8 ( ) > 16 {
406
508
return Err ( SegwitHrpstringError :: InvalidWitnessVersion ( witness_version) ) ;
407
509
}
@@ -429,9 +531,10 @@ impl<'s> SegwitHrpstring<'s> {
429
531
#[ inline]
430
532
pub fn new_bech32 ( s : & ' s str ) -> Result < Self , SegwitHrpstringError > {
431
533
let unchecked = UncheckedHrpstring :: new ( s) ?;
534
+ let data_part = unchecked. data_part_ascii ( ) ;
432
535
433
536
// Unwrap ok since check_characters (in `Self::new`) checked the bech32-ness of this char.
434
- let witness_version = Fe32 :: from_char ( unchecked . data [ 0 ] . into ( ) ) . unwrap ( ) ;
537
+ let witness_version = Fe32 :: from_char ( data_part [ 0 ] . into ( ) ) . unwrap ( ) ;
435
538
if witness_version. to_u8 ( ) > 16 {
436
539
return Err ( SegwitHrpstringError :: InvalidWitnessVersion ( witness_version) ) ;
437
540
}
@@ -456,6 +559,25 @@ impl<'s> SegwitHrpstring<'s> {
456
559
#[ inline]
457
560
pub fn witness_version ( & self ) -> Fe32 { self . witness_version }
458
561
562
+ /// Returns a partial slice of the data part, as ASCII bytes, everything after the witness
563
+ /// version and before the checksum.
564
+ ///
565
+ /// The byte values are guaranteed to be valid bech32 characters.
566
+ ///
567
+ /// # Examples
568
+ ///
569
+ /// ```
570
+ /// use bech32::{Bech32, primitives::decode::SegwitHrpstring};
571
+ ///
572
+ /// let addr = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
573
+ /// let ascii = "ar0srrr7xfkvy5l643lydnw9re59gtzz";
574
+ ///
575
+ /// let segwit = SegwitHrpstring::new(&addr).unwrap();
576
+ /// assert!(segwit.data_part_ascii_no_witver_no_checksum().iter().eq(ascii.as_bytes().iter()))
577
+ /// ```
578
+ #[ inline]
579
+ pub fn data_part_ascii_no_witver_no_checksum ( & self ) -> & [ u8 ] { self . ascii }
580
+
459
581
/// Returns an iterator that yields the data part, excluding the witness version, of the parsed
460
582
/// bech32 encoded string.
461
583
///
@@ -465,12 +587,12 @@ impl<'s> SegwitHrpstring<'s> {
465
587
/// Use `self.witness_version()` to get the witness version.
466
588
#[ inline]
467
589
pub fn byte_iter ( & self ) -> ByteIter {
468
- ByteIter { iter : AsciiToFe32Iter { iter : self . data . iter ( ) . copied ( ) } . fes_to_bytes ( ) }
590
+ ByteIter { iter : AsciiToFe32Iter { iter : self . ascii . iter ( ) . copied ( ) } . fes_to_bytes ( ) }
469
591
}
470
592
}
471
593
472
- /// Checks whether a given HRP string has data characters in the bech32 alphabet (incl. checksum
473
- /// characters), and that the whole string has consistent casing (hrp, data, and checksum ).
594
+ /// Checks whether a given HRP string has data part characters in the bech32 alphabet (incl.
595
+ /// checksum characters), and that the whole string has consistent casing (hrp and data part ).
474
596
///
475
597
/// # Returns
476
598
///
0 commit comments