@@ -398,14 +398,15 @@ impl fmt::Display for Address {
398
398
Network :: Testnet | Network :: Signet => "tb" ,
399
399
Network :: Regtest => "bcrt" ,
400
400
} ;
401
+ let bech_ver = if ver. to_u8 ( ) > 0 { bech32:: Variant :: Bech32m } else { bech32:: Variant :: Bech32 } ;
401
402
let mut upper_writer;
402
403
let writer = if fmt. alternate ( ) {
403
404
upper_writer = UpperWriter ( fmt) ;
404
405
& mut upper_writer as & mut dyn fmt:: Write
405
406
} else {
406
407
fmt as & mut dyn fmt:: Write
407
408
} ;
408
- let mut bech32_writer = bech32:: Bech32Writer :: new ( hrp, writer) ?;
409
+ let mut bech32_writer = bech32:: Bech32Writer :: new ( hrp, bech_ver , writer) ?;
409
410
bech32:: WriteBase32 :: write_u5 ( & mut bech32_writer, ver) ?;
410
411
bech32:: ToBase32 :: write_base32 ( & prog, & mut bech32_writer)
411
412
}
@@ -448,7 +449,7 @@ impl FromStr for Address {
448
449
} ;
449
450
if let Some ( network) = bech32_network {
450
451
// decode as bech32
451
- let ( _, payload) = bech32:: decode ( s) ?;
452
+ let ( _, payload, variant ) = bech32:: decode ( s) ?;
452
453
if payload. is_empty ( ) {
453
454
return Err ( Error :: EmptyBech32Payload ) ;
454
455
}
@@ -472,6 +473,12 @@ impl FromStr for Address {
472
473
return Err ( Error :: InvalidSegwitV0ProgramLength ( program. len ( ) ) ) ;
473
474
}
474
475
476
+ // Bech32 encoding check
477
+ if ( version. to_u8 ( ) > 0 && variant != bech32:: Variant :: Bech32m ) ||
478
+ ( version. to_u8 ( ) == 0 && variant != bech32:: Variant :: Bech32 ) {
479
+ return Err ( Error :: InvalidWitnessVersion ( version. to_u8 ( ) ) )
480
+ }
481
+
475
482
return Ok ( Address {
476
483
payload : Payload :: WitnessProgram {
477
484
version : version,
@@ -681,14 +688,17 @@ mod tests {
681
688
}
682
689
683
690
#[ test]
684
- fn test_bip173_vectors ( ) {
691
+ fn test_bip173_350_vectors ( ) {
692
+ // Test vectors valid under both BIP-173 and BIP-350
685
693
let valid_vectors = [
686
694
( "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4" , "0014751e76e8199196d454941c45d1b3a323f1433bd6" ) ,
687
695
( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" , "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262" ) ,
688
- ( "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx " , "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6" ) ,
689
- ( "BC1SW50QA3JX3S " , "6002751e" ) ,
690
- ( "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj " , "5210751e76e8199196d454941c45d1b3a323" ) ,
696
+ ( "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y " , "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6" ) ,
697
+ ( "BC1SW50QGDZ25J " , "6002751e" ) ,
698
+ ( "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs " , "5210751e76e8199196d454941c45d1b3a323" ) ,
691
699
( "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy" , "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" ) ,
700
+ ( "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c" , "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" ) ,
701
+ ( "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0" , "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" )
692
702
] ;
693
703
for vector in & valid_vectors {
694
704
let addr: Address = vector. 0 . parse ( ) . unwrap ( ) ;
@@ -697,16 +707,59 @@ mod tests {
697
707
}
698
708
699
709
let invalid_vectors = [
710
+ // 1. BIP-350 test vectors
711
+ // Invalid human-readable part
712
+ "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut" ,
713
+ // Invalid checksums (Bech32 instead of Bech32m):
714
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd" ,
715
+ "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf" ,
716
+ "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL" ,
717
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh" ,
718
+ "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47" ,
719
+ // Invalid character in checksum
720
+ "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4" ,
721
+ // Invalid witness version
722
+ "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R" ,
723
+ // Invalid program length (1 byte)
724
+ "bc1pw5dgrnzv" ,
725
+ // Invalid program length (41 bytes)
726
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav" ,
727
+ // Invalid program length for witness version 0 (per BIP141)
728
+ "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P" ,
729
+ // Mixed case
730
+ "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq" ,
731
+ // zero padding of more than 4 bits
732
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf" ,
733
+ // Non-zero padding in 8-to-5 conversion
734
+ "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j" ,
735
+ // Empty data section
736
+ "bc1gmk9yu" ,
737
+
738
+ // 2. BIP-173 test vectors
739
+ // Invalid human-readable part
700
740
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty" ,
741
+ // Invalid checksum
701
742
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5" ,
743
+ // Invalid witness version
702
744
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2" ,
745
+ // Invalid program length
703
746
"bc1rw5uspcuh" ,
747
+ // Invalid program length
704
748
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90" ,
749
+ // Invalid program length for witness version 0 (per BIP141)
705
750
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P" ,
751
+ // Mixed case
706
752
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7" ,
753
+ // zero padding of more than 4 bits
707
754
"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du" ,
755
+ // Non-zero padding in 8-to-5 conversion
708
756
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv" ,
709
- "bc1gmk9yu" ,
757
+ // Final test for empty data section is the same as above in BIP-350
758
+
759
+ // 3. BIP-173 valid test vectors obsolete by BIP-350
760
+ "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx" ,
761
+ "BC1SW50QA3JX3S" ,
762
+ "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj" ,
710
763
] ;
711
764
for vector in & invalid_vectors {
712
765
assert ! ( vector. parse:: <Address >( ) . is_err( ) ) ;
0 commit comments