@@ -146,6 +146,7 @@ pub struct Bech32Writer<'b> {
146
146
out : & ' b mut [ u8 ] ,
147
147
bytes_written : usize ,
148
148
chk : u32 ,
149
+ variant : Variant ,
149
150
}
150
151
151
152
#[ derive( Debug ) ]
@@ -164,11 +165,12 @@ impl<'b> Bech32Writer<'b> {
164
165
] ;
165
166
166
167
/// Creatw a new bech32 writer
167
- pub fn new ( hrp : & str , out : & ' b mut [ u8 ] ) -> Result < Self , Bech32WriterError > {
168
+ pub fn new ( hrp : & str , out : & ' b mut [ u8 ] , variant : Variant ) -> Result < Self , Bech32WriterError > {
168
169
let mut this = Self {
169
170
chk : 1 ,
170
171
out,
171
172
bytes_written : 0 ,
173
+ variant,
172
174
} ;
173
175
174
176
let hrp = hrp. as_bytes ( ) ;
@@ -274,7 +276,7 @@ impl<'b> Bech32Writer<'b> {
274
276
self . polymod_step ( u5 ( 0 ) )
275
277
}
276
278
277
- let plm: u32 = self . chk ^ 1 ;
279
+ let plm: u32 = self . chk ^ self . variant . constant ( ) ;
278
280
279
281
self . check_rem_out ( 6 ) ?;
280
282
for p in 0 ..6 {
@@ -308,8 +310,9 @@ pub fn encode(
308
310
hrp : & str ,
309
311
data : impl AsRef < [ u8 ] > ,
310
312
out : & mut [ u8 ] ,
313
+ variant : Variant ,
311
314
) -> Result < usize , Bech32WriterError > {
312
- let mut encoder = Bech32Writer :: new ( hrp, out) ?;
315
+ let mut encoder = Bech32Writer :: new ( hrp, out, variant ) ?;
313
316
encoder. write ( data) ?;
314
317
encoder. finalize ( )
315
318
}
@@ -318,6 +321,28 @@ pub const fn estimate_size(hrp_len: usize, data_len: usize) -> usize {
318
321
Bech32Writer :: estimate_size ( hrp_len, data_len)
319
322
}
320
323
324
+
325
+ /// Used for encoding operations for the two variants of Bech32
326
+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug ) ]
327
+ pub enum Variant {
328
+ /// The original Bech32 described in [BIP-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
329
+ Bech32 ,
330
+ /// The improved Bech32m variant described in [BIP-0350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)
331
+ Bech32m ,
332
+ }
333
+
334
+ const BECH32_CONST : u32 = 1 ;
335
+ const BECH32M_CONST : u32 = 0x2bc8_30a3 ;
336
+
337
+ impl Variant {
338
+ fn constant ( self ) -> u32 {
339
+ match self {
340
+ Variant :: Bech32 => BECH32_CONST ,
341
+ Variant :: Bech32m => BECH32M_CONST ,
342
+ }
343
+ }
344
+ }
345
+
321
346
#[ cfg( test) ]
322
347
mod tests {
323
348
use super :: * ;
@@ -343,7 +368,7 @@ mod tests {
343
368
fn encode_with_writer ( ) {
344
369
let mut out = [ 0 ; Bech32Writer :: estimate_size ( HRP . len ( ) , INPUT . len ( ) ) ] ;
345
370
346
- let mut encoder = Bech32Writer :: new ( HRP , & mut out) . expect ( "unable to write HRP" ) ;
371
+ let mut encoder = Bech32Writer :: new ( HRP , & mut out, Variant :: Bech32 ) . expect ( "unable to write HRP" ) ;
347
372
encoder. write ( & INPUT ) . expect ( "unable to write data" ) ;
348
373
let written = encoder. finalize ( ) . expect ( "unable to finalize" ) ;
349
374
@@ -355,8 +380,184 @@ mod tests {
355
380
#[ test]
356
381
fn encode_with_fn ( ) {
357
382
let mut out = [ 0 ; estimate_size ( HRP . len ( ) , INPUT . len ( ) ) ] ;
358
- let written = encode ( HRP , & INPUT , & mut out) . expect ( "unable to encode bech32" ) ;
383
+ let written = encode ( HRP , & INPUT , & mut out, Variant :: Bech32 ) . expect ( "unable to encode bech32" ) ;
359
384
360
385
assert_eq ! ( & out[ ..written] , EXPECTED . as_bytes( ) ) ;
361
386
}
362
- }
387
+
388
+ const HRPS : [ & str ; 5 ] =[ "a" ,
389
+ "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio" ,
390
+ "abcdef" ,
391
+ "1" ,
392
+ "split"
393
+ ] ;
394
+
395
+ const BECH32_ENCODINGS : [ & str ; 5 ] = [ "A12UEL5L" ,
396
+ "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs" ,
397
+ "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw" ,
398
+ "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j" ,
399
+ "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w" ] ;
400
+
401
+ /*
402
+ const BECH32_INPUTS: [&[u8];5] = [& *b"",
403
+ & *b"",
404
+ & [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
405
+ 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],
406
+ & [0;82],
407
+ & *b""];
408
+ */
409
+
410
+ #[ test]
411
+ fn valid_checksum_bech32_0 ( ) {
412
+ const INPUT : [ u8 ; 0 ] = * b"" ;
413
+ let mut out = [ 0 ; estimate_size ( HRPS [ 0 ] . len ( ) ,
414
+ INPUT . len ( ) ) ] ;
415
+ encode ( HRPS [ 0 ] , & INPUT , & mut out, Variant :: Bech32 )
416
+ . expect ( "unable to encode bech32" ) ;
417
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
418
+
419
+ assert_eq ! ( BECH32_ENCODINGS [ 0 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
420
+ }
421
+
422
+ #[ test]
423
+ fn valid_checksum_bech32_1 ( ) {
424
+ const INPUT : [ u8 ; 0 ] = * b"" ;
425
+ let mut out = [ 0 ; estimate_size ( HRPS [ 1 ] . len ( ) , INPUT . len ( ) ) ] ;
426
+ encode ( HRPS [ 1 ] , & INPUT , & mut out, Variant :: Bech32 )
427
+ . expect ( "unable to encode bech32" ) ;
428
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
429
+
430
+ assert_eq ! ( BECH32_ENCODINGS [ 1 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
431
+ }
432
+
433
+
434
+ #[ test] #[ ignore]
435
+ fn valid_checksum_bech32_2 ( ) {
436
+ const INPUT : [ u8 ; 32 ] = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ,
437
+ 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 ] ;
438
+
439
+ let mut out = [ 0 ; estimate_size ( HRPS [ 2 ] . len ( ) , INPUT . len ( ) ) ] ;
440
+ let written = encode ( HRPS [ 2 ] , & INPUT , & mut out, Variant :: Bech32 )
441
+ . expect ( "unable to encode bech32" ) ;
442
+ let encoded = std:: str:: from_utf8 ( & out[ ..written] ) . expect ( "invalid utf8 bytes" ) ;
443
+
444
+ assert_eq ! ( BECH32_ENCODINGS [ 2 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
445
+ }
446
+
447
+ #[ test] #[ ignore]
448
+ fn valid_checksum_bech32_3 ( ) {
449
+ const INPUT : [ u8 ; 82 ] = [ 0 ; 82 ] ;
450
+ let mut out = [ 0 ; estimate_size ( HRPS [ 3 ] . len ( ) , INPUT . len ( ) ) ] ;
451
+ let written = encode ( HRPS [ 3 ] , & INPUT , & mut out, Variant :: Bech32 )
452
+ . expect ( "unable to encode bech32" ) ;
453
+ let encoded = std:: str:: from_utf8 ( & out[ ..written] ) . expect ( "invalid utf8 bytes" ) ;
454
+
455
+ assert_eq ! ( BECH32_ENCODINGS [ 3 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
456
+ }
457
+
458
+ #[ test] #[ ignore]
459
+ fn valid_checksum_bech32_4 ( ) {
460
+ const INPUT : [ u8 ; 0 ] = * b"" ;
461
+ let mut out = [ 0 ; estimate_size ( HRPS [ 4 ] . len ( ) , INPUT . len ( ) ) ] ;
462
+ encode ( HRPS [ 4 ] , & INPUT , & mut out, Variant :: Bech32 )
463
+ . expect ( "unable to encode bech32" ) ;
464
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
465
+
466
+ assert_eq ! ( BECH32_ENCODINGS [ 4 ] . to_lowercase( ) ,
467
+ encoded. to_lowercase( ) ) ;
468
+ }
469
+
470
+
471
+
472
+ const BECH32M_HRPS : [ & str ; 7 ] =[ "a" , "a" ,
473
+ "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber1" ,
474
+ "abcdef" ,
475
+ "1" ,
476
+ "split" ,
477
+ "?"
478
+ ] ;
479
+ const BECH32M_ENCODINGS : [ & str ; 7 ] =[ "A1LQFN3A" , "a1lqfn3a" ,
480
+ "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6" ,
481
+ "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx" ,
482
+ "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8" ,
483
+ "split1checkupstagehandshakeupstreamerranterredcaperredlc445v" ,
484
+ "?1v759aa" ] ;
485
+
486
+ #[ test]
487
+ fn valid_checksum_bech32m_0 ( ) {
488
+ const INPUT : [ u8 ; 0 ] = * b"" ;
489
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 0 ] . len ( ) , INPUT . len ( ) ) ] ;
490
+ encode ( BECH32M_HRPS [ 0 ] , & INPUT , & mut out, Variant :: Bech32m )
491
+ . expect ( "unable to encode bech32m" ) ;
492
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
493
+
494
+ assert_eq ! ( BECH32M_ENCODINGS [ 0 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
495
+ }
496
+
497
+ #[ test]
498
+ fn valid_checksum_bech32m_1 ( ) {
499
+ const INPUT : [ u8 ; 0 ] = * b"" ;
500
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 1 ] . len ( ) , INPUT . len ( ) ) ] ;
501
+ encode ( BECH32M_HRPS [ 1 ] , & INPUT , & mut out, Variant :: Bech32m )
502
+ . expect ( "unable to encode bech32m" ) ;
503
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
504
+
505
+ assert_eq ! ( BECH32M_ENCODINGS [ 1 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
506
+ }
507
+
508
+ #[ test]
509
+ fn valid_checksum_bech32m_2 ( ) {
510
+ const INPUT : [ u8 ; 0 ] = * b"" ;
511
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 2 ] . len ( ) , INPUT . len ( ) ) ] ;
512
+ encode ( BECH32M_HRPS [ 2 ] , & INPUT , & mut out, Variant :: Bech32m )
513
+ . expect ( "unable to encode bech32m" ) ;
514
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
515
+
516
+ assert_eq ! ( BECH32M_ENCODINGS [ 2 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
517
+ }
518
+
519
+ #[ test] #[ ignore]
520
+ fn valid_checksum_bech32m_3 ( ) {
521
+ const INPUT : [ u8 ; 32 ] = [ 31 , 30 , 29 , 28 , 27 , 26 , 25 , 24 , 23 , 22 , 21 , 20 , 19 , 18 , 17 , 16 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ;
522
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 3 ] . len ( ) , INPUT . len ( ) ) ] ;
523
+ encode ( BECH32M_HRPS [ 3 ] , & INPUT , & mut out, Variant :: Bech32m )
524
+ . expect ( "unable to encode bech32m" ) ;
525
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
526
+
527
+ assert_eq ! ( BECH32M_ENCODINGS [ 3 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
528
+ }
529
+
530
+ #[ test] #[ ignore]
531
+ fn valid_checksum_bech32m_4 ( ) {
532
+ const INPUT : [ u8 ; 82 ] = [ 31 ; 82 ] ;
533
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 4 ] . len ( ) , INPUT . len ( ) ) ] ;
534
+ encode ( BECH32M_HRPS [ 4 ] , & INPUT , & mut out, Variant :: Bech32m )
535
+ . expect ( "unable to encode bech32m" ) ;
536
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
537
+
538
+ assert_eq ! ( BECH32M_ENCODINGS [ 4 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
539
+ }
540
+
541
+ #[ test] #[ ignore]
542
+ fn valid_checksum_bech32m_5 ( ) {
543
+ const INPUT : [ u8 ; 48 ] = [ 24 , 23 , 25 , 24 , 22 , 28 , 1 , 16 , 11 , 29 , 8 , 25 , 23 , 29 , 19 , 13 , 16 , 23 , 29 , 22 , 25 , 28 , 1 , 16 , 11 , 3 , 25 , 29 , 27 , 25 , 3 , 3 , 29 , 19 , 11 , 25 , 3 , 3 , 25 , 13 , 24 , 29 , 1 , 25 , 3 , 3 , 25 , 13 ] ;
544
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 5 ] . len ( ) , INPUT . len ( ) ) ] ;
545
+ let written = encode ( BECH32M_HRPS [ 5 ] , & INPUT , & mut out, Variant :: Bech32m )
546
+ . expect ( "unable to encode bech32m" ) ;
547
+ let encoded = std:: str:: from_utf8 ( & out[ ..written] ) . expect ( "invalid utf8 bytes" ) ;
548
+
549
+ assert_eq ! ( BECH32M_ENCODINGS [ 5 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
550
+ }
551
+
552
+ #[ test]
553
+ fn valid_checksum_bech32m_6 ( ) {
554
+ const INPUT : [ u8 ; 0 ] = * b"" ;
555
+ let mut out = [ 0 ; estimate_size ( BECH32M_HRPS [ 6 ] . len ( ) , INPUT . len ( ) ) ] ;
556
+ encode ( BECH32M_HRPS [ 6 ] , & INPUT , & mut out, Variant :: Bech32m )
557
+ . expect ( "unable to encode bech32m" ) ;
558
+ let encoded = std:: str:: from_utf8 ( & out) . expect ( "invalid utf8 bytes" ) ;
559
+
560
+ assert_eq ! ( BECH32M_ENCODINGS [ 6 ] . to_lowercase( ) , encoded. to_lowercase( ) ) ;
561
+ }
562
+
563
+ }
0 commit comments