Created
April 25, 2022 06:28
-
-
Save grondilu/b21620bb55c15208990db3a90d405247 to your computer and use it in GitHub Desktop.
Bech32 in raku
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
grammar Bech32 { | |
constant @data-charset = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'.comb; | |
constant %data-charset = @data-charset.pairs.invert; | |
sub polymod(@values --> UInt) { | |
constant @gen = 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3; | |
my uint32 $chk = 1; | |
for @values -> $v { | |
my $b = $chk +> 25; | |
$chk = ($chk +& 0x1ffffff) +< 5 +^ $v; | |
$chk +^= (($b +> $_) +& 1) ?? @gen[$_] !! 0 for ^5; | |
} | |
return $chk; | |
} | |
sub hrp-expand(Str $s --> Array) { | |
[ord($_) +> 5 for $s.comb] | |
.append(0) | |
.append: | |
[ord($_) +& 31 for $s.comb] | |
} | |
regex TOP { | |
^ <hrp> '1' <data> $ | |
<?{ polymod(hrp-expand(~$<hrp>).append: $<data>.made) == 1|0x2bc830a3 }> | |
} | |
regex hrp { <ascii> ** 1..83 <?{ 33 ≤ $/.ords.all ≤ 126 }> } | |
regex data { (<@data-charset>) ** 6..* { make %data-charset{$/[0]} } } | |
token ascii { . <?{ try $/.encode("ascii"); not $! }> } | |
} | |
use Test; | |
subtest { | |
ok Bech32.parse(.lc), $_ for < | |
A12UEL5L | |
a12uel5l | |
an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs | |
abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw | |
11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j | |
split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w | |
?1ezyfcl | |
>; | |
nok Bech32.parse(.key.lc), "{.key} : {.value}" for | |
chr(0x20) ~ "1nwldj5" => "HRP character out of range", | |
chr(0x7F) ~ "1axkwrx" => "HRP character out of range", | |
chr(0x80) ~ "1eym55h" => "HRP character out of range", | |
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx" => "overall max length exceeded", | |
"pzry9x0s0muk" => "No separator character", | |
"1pzry9x0s0muk" => "Empty HRP", | |
"x1b4n0q5v" => "Invalid data character", | |
"li1dgmt3" => "Too short checksum", | |
"de1lg7wt" ~ chr(0xFF) => "Invalid character in checksum", | |
"A1G7SGD8" => "checksum calculated with uppercase form of HRP", | |
"10a06t8" => "empty HRP", | |
"1qzzfhee" => "empty HRP", | |
; | |
}, "bip-0173"; | |
subtest { | |
ok Bech32.parse(.lc), $_ for < | |
A1LQFN3A | |
a1lqfn3a | |
an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6 | |
abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx | |
11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8 | |
split1checkupstagehandshakeupstreamerranterredcaperredlc445v | |
?1v759aa | |
>; | |
nok Bech32.parse(.key.lc), "{.key} : {.value}" for | |
chr(0x20) ~ "1xj0phk" => "HRP character out of range", | |
chr(0x7F) ~ "1g6xzxy" => "HRP character out of range", | |
chr(0x80) ~ "1vctc34" => "HRP character out of range", | |
"an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4" => "overall max length exceeded", | |
"qyrz8wqd2c9m" => "No separator character", | |
"1qyrz8wqd2c9m" => "Empty HRP", | |
"y1b0jsk6g" => "Invalid data character", | |
"lt1igcx5c0" => "Invalid data character", | |
"in1muywd" => "Too short checksum", | |
"mm1crxm3i" => "Invalid character in checksum", | |
"au1s5cgom" => "Invalid character in checksum", | |
"M1VUXWEZ" => "checksum calculated with uppercase form of HRP", | |
"16plkw9" => "empty HRP", | |
"1p2gdwpf" => "empty HRP"; | |
}, "bip-0350"; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment